소스 검색

initial commit of vertx-web-kotlin-dsljson benchmark (#9172)

* initial commit of vertx-web-kotlin-dsljson benchmark

* removed dagger. improved query performance.
Andrew McCloskey 1 년 전
부모
커밋
848d684076
37개의 변경된 파일1683개의 추가작업 그리고 0개의 파일을 삭제
  1. 9 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/.gitattributes
  2. 36 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md
  3. 47 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json
  4. 86 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts
  5. 47 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh
  6. 1 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties
  7. BIN
      frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.jar
  8. 7 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties
  9. 252 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew
  10. 94 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat
  11. 1 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts
  12. 50 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt
  13. 56 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt
  14. 88 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt
  15. 7 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt
  16. 23 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt
  17. 84 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt
  18. 57 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt
  19. 15 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt
  20. 57 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt
  21. 15 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt
  22. 56 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/WorldHandler.kt
  23. 362 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/BufferOutputStream.kt
  24. 15 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/JsonResource.kt
  25. 14 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt
  26. 7 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt
  27. 14 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt
  28. 14 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt
  29. 19 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt
  30. 16 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt
  31. 14 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt
  32. 12 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt
  33. 6 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/http-server-options.json
  34. 13 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/log4j2.xml
  35. 15 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json
  36. 37 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile
  37. 37 0
      frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile

+ 9 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/.gitattributes

@@ -0,0 +1,9 @@
+#
+# https://help.github.com/articles/dealing-with-line-endings/
+#
+# Linux start script should use lf
+/gradlew        text eol=lf
+
+# These are Windows script files and should use crlf
+*.bat           text eol=crlf
+

+ 36 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md

@@ -0,0 +1,36 @@
+# Vert.x-Web Kotlin Dsljson Benchmarking Test
+
+Vert.x-Web in Kotlin with Dsljson serialization
+
+The code is written as a realistic server implementation:
+- Code is organized logically into packages
+- Repositories are created for each database entity to handler all operations pertaining to a specific table
+- Handlers map to the logical entities which they serve
+- JSON serialization is provided via Dsljson
+  - Doing this effectively required a custom Vert.x Buffer implementation that also extended OutputStream in order to rely on the efficient Vert.x heap memory pool instead of building a novel implementation.
+
+## Test URLs
+
+### JSON
+
+http://localhost:8080/json
+
+### PLAINTEXT
+
+http://localhost:8080/plaintext
+
+### DB
+
+http://localhost:8080/db
+
+### QUERY
+
+http://localhost:8080/query?queries=
+
+### UPDATE
+
+http://localhost:8080/update?queries=
+
+### FORTUNES
+
+http://localhost:8080/fortunes

+ 47 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json

@@ -0,0 +1,47 @@
+{
+  "framework": "vertx-web-kotlin-dsljson",
+  "tests": [
+    {
+      "default": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "None",
+        "framework": "vertx-web",
+        "language": "Kotlin",
+        "flavor": "None",
+        "orm": "Raw",
+        "platform": "Vert.x",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "vertx-web-kotlin-dsljson",
+        "notes": "",
+        "versus": "vertx-web"
+      },
+      "postgresql": {
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "postgres",
+        "framework": "vertx-web",
+        "language": "Kotlin",
+        "flavor": "None",
+        "orm": "Raw",
+        "platform": "Vert.x",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "vertx-web-kotlin-dsljson-postgresql",
+        "notes": "",
+        "versus": "vertx-web-postgres"
+      }
+    }
+  ]
+}

+ 86 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts

@@ -0,0 +1,86 @@
+import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
+plugins {
+    kotlin("jvm") version "1.9.22"
+    kotlin("kapt") version "1.9.22"
+    application
+    id("com.github.johnrengelman.shadow") version "7.1.2"
+}
+
+group = "com.example"
+version = "1.0.0-SNAPSHOT"
+
+repositories {
+    mavenCentral()
+}
+
+java {
+    toolchain {
+        languageVersion.set(JavaLanguageVersion.of(21))
+    }
+}
+
+kotlin {
+    compilerOptions {
+        jvmTarget = JvmTarget.JVM_21
+    }
+    jvmToolchain(21)
+}
+
+val mainClassName = "com.example.starter.App"
+
+val vertxVersion = "4.5.9"
+val nettyVersion = "4.1.112.Final"
+val scramVersion = "2.1"
+val dslJsonVersion = "2.0.2"
+val htmlFlowVersion = "4.6"
+val log4jVersion = "2.23.1"
+
+application {
+    mainClass = mainClassName
+}
+
+dependencies {
+    listOfNotNull(
+        // Kotlin
+        kotlin("stdlib-jdk8"),
+        kotlin("reflect"),
+
+        // Vertx
+        platform("io.vertx:vertx-stack-depchain:$vertxVersion"),
+        "io.vertx:vertx-core",
+        "io.vertx:vertx-web",
+        "io.vertx:vertx-pg-client",
+        "io.vertx:vertx-lang-kotlin",
+        "io.vertx:vertx-lang-kotlin-coroutines",
+
+        // Netty
+        "io.netty:netty-transport-native-epoll:$nettyVersion:linux-x86_64",
+
+        // Postgres
+        "com.ongres.scram:client:$scramVersion",
+
+        // dsljson
+        "com.dslplatform:dsl-json:$dslJsonVersion",
+
+        // HtmlFlow
+        "com.github.xmlet:htmlflow:$htmlFlowVersion",
+
+        // Logging
+        "org.apache.logging.log4j:log4j-core:$log4jVersion",
+        "org.apache.logging.log4j:log4j-api:$log4jVersion",
+        "org.apache.logging.log4j:log4j-api-kotlin:1.4.0",
+        "com.lmax:disruptor:4.0.0",
+    ).map { implementation(it) }
+
+    listOf(
+        "com.dslplatform:dsl-json:$dslJsonVersion",
+        "org.apache.logging.log4j:log4j-core:$log4jVersion",
+    ).map { kapt(it) }
+}
+
+tasks.withType<ShadowJar> {
+    archiveClassifier = "fat"
+    mergeServiceFiles()
+}

+ 47 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh

@@ -0,0 +1,47 @@
+#!/bin/bash
+
+NUM_PROCESSORS=$((`grep --count ^processor /proc/cpuinfo`))
+
+JVM_OPTS="-server \
+  -Xms2G \
+  -Xmx2G \
+  -XX:+UseParallelGC \
+  -XX:InitialCodeCacheSize=512m \
+  -XX:ReservedCodeCacheSize=512m \
+  -XX:MaxInlineLevel=20 \
+  -XX:+AlwaysPreTouch \
+  -XX:+UseNUMA \
+  -Dvertx.disableMetrics=true \
+  -Dvertx.disableH2c=true \
+  -Dvertx.disableWebsockets=true \
+  -Dvertx.flashPolicyHandler=false \
+  -Dvertx.threadChecks=false \
+  -Dvertx.disableContextTimings=true \
+  -Dvertx.disableTCCL=true \
+  -Dvertx.disableHttpHeadersValidation=true \
+  -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \
+  -Dio.netty.buffer.checkBounds=false \
+  -Dio.netty.buffer.checkAccessible=false \
+  -Dtfb.hasDB=false"
+
+JAR_PATH="./build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar"
+
+VERTX_ARGS="-instances 1"
+
+cleanup() {
+    echo "Caught SIGINT signal. Stopping the Java program..."
+    if [ ! -z "$JAVA_PID" ]; then
+        kill -SIGTERM "$JAVA_PID"
+        wait "$JAVA_PID"
+    fi
+    exit 0
+}
+
+trap cleanup SIGINT
+
+java $JVM_OPTS -jar $JAR_PATH $VERTX_ARGS &
+JAVA_PID=$!
+
+echo "Server PID: $JAVA_PID"
+
+wait "$JAVA_PID"

+ 1 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties

@@ -0,0 +1 @@
+org.gradle.parallel=true

BIN
frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.jar


+ 7 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists

+ 252 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew

@@ -0,0 +1,252 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# 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
+#
+#      https://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.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+    echo "$*"
+} >&2
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD=$JAVA_HOME/jre/sh/java
+    else
+        JAVACMD=$JAVA_HOME/bin/java
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD=java
+    if ! command -v java >/dev/null 2>&1
+    then
+        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
+        fi
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
+    done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+#     and any embedded shellness will be escaped.
+#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+#     treated as '${Hostname}' itself on the command line.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+    die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
+
+exec "$JAVACMD" "$@"

+ 94 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat

@@ -0,0 +1,94 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega

+ 1 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts

@@ -0,0 +1 @@
+rootProject.name = "vertx-web-kotlin-dsljson-benchmark"

+ 50 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt

@@ -0,0 +1,50 @@
+package com.example.starter
+
+import com.example.starter.utils.PeriodicDateResolver
+import com.example.starter.utils.block
+import io.vertx.core.Vertx
+import io.vertx.core.impl.cpu.CpuCoreSensor
+import io.vertx.kotlin.core.deploymentOptionsOf
+import io.vertx.kotlin.core.vertxOptionsOf
+import kotlin.time.Duration.Companion.seconds
+import org.apache.logging.log4j.kotlin.Logging
+
+object App : Logging {
+    private const val SERVER_NAME = "Vert.x-Web Benchmark"
+
+    @JvmStatic
+    fun main(args: Array<out String?>?) {
+        val numCores = CpuCoreSensor.availableProcessors()
+
+        val vertx = Vertx.vertx(
+            vertxOptionsOf(
+                eventLoopPoolSize = numCores,
+                preferNativeTransport = true,
+            )
+        )
+        vertx.exceptionHandler {
+            logger.error(it) { "Vertx unexpected exception:" }
+            vertx.close().block(5.seconds)
+        }
+
+        // Add the SIGINT handler
+        Runtime.getRuntime().addShutdownHook(Thread {
+            vertx.close().block(5.seconds)
+        })
+
+        // Initialize the periodic date resolver
+        PeriodicDateResolver.init(vertx)
+
+        // Check the type of test that is being run
+        val hasDb = System.getProperty("tfb.hasDB")?.toBoolean() ?: false
+
+        vertx.deployVerticle(
+            { if (hasDb) PostgresVerticle() else BasicVerticle() },
+            deploymentOptionsOf(
+                instances = numCores,
+            )
+        )
+
+        logger.info("$SERVER_NAME started.")
+    }
+}

+ 56 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt

@@ -0,0 +1,56 @@
+package com.example.starter
+
+import com.example.starter.handlers.DefaultHandler
+import com.example.starter.handlers.MessageHandler
+import com.example.starter.io.JsonResource
+import com.example.starter.utils.isConnectionReset
+import io.vertx.core.AbstractVerticle
+import io.vertx.core.Promise
+import io.vertx.core.http.HttpServerOptions
+import io.vertx.ext.web.Router
+import org.apache.logging.log4j.kotlin.Logging
+
+class BasicVerticle : AbstractVerticle() {
+    override fun start(startPromise: Promise<Void>) {
+        val defaultHandler = DefaultHandler()
+        val messageHandler = MessageHandler()
+
+        val router = Router.router(vertx)
+
+        router
+            .get("/plaintext")
+            .handler(defaultHandler::plaintext)
+
+        router
+            .get("/json")
+            .handler(messageHandler::readDefaultMessage)
+
+        val server = vertx
+            .createHttpServer(HTTP_SERVER_OPTIONS)
+            .requestHandler(router)
+            .exceptionHandler {
+                if (it.isConnectionReset()) return@exceptionHandler
+                logger.error(it) { "Exception in HttpServer" }
+            }
+
+        server
+            .listen()
+            .onSuccess {
+                logger.info { "HTTP server started on port 8080" }
+                startPromise.complete()
+            }
+            .onFailure {
+                logger.error(it.cause) { "Failed to start" }
+                startPromise.fail(it.cause)
+            }
+    }
+
+    companion object : Logging {
+        private const val HTTP_SERVER_OPTIONS_RESOURCE = "http-server-options.json"
+
+        private val HTTP_SERVER_OPTIONS: HttpServerOptions by lazy {
+            val json = JsonResource.of(HTTP_SERVER_OPTIONS_RESOURCE)
+            HttpServerOptions(json)
+        }
+    }
+}

+ 88 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt

@@ -0,0 +1,88 @@
+package com.example.starter
+
+import com.example.starter.db.FortuneRepository
+import com.example.starter.db.WorldRepository
+import com.example.starter.handlers.FortuneHandler
+import com.example.starter.handlers.WorldHandler
+import com.example.starter.io.JsonResource
+import com.example.starter.utils.array
+import com.example.starter.utils.isConnectionReset
+import io.vertx.core.AbstractVerticle
+import io.vertx.core.Future
+import io.vertx.core.Promise
+import io.vertx.core.http.HttpServerOptions
+import io.vertx.ext.web.Router
+import io.vertx.pgclient.PgConnectOptions
+import io.vertx.pgclient.PgConnection
+import org.apache.logging.log4j.kotlin.Logging
+
+class PostgresVerticle : AbstractVerticle() {
+    override fun start(startPromise: Promise<Void>) {
+        Future.all(
+            PgConnection.connect(vertx, PG_CONNECT_OPTIONS),
+            PgConnection.connect(vertx, PG_CONNECT_OPTIONS),
+        )
+            .onSuccess { cf ->
+                val pool = cf.array<PgConnection>()
+
+                val fortuneHandler = FortuneHandler(FortuneRepository(pool))
+                val worldHandler = WorldHandler(WorldRepository(pool))
+
+                val router = Router.router(vertx)
+
+                router
+                    .get("/fortunes")
+                    .handler(fortuneHandler::templateFortunes)
+
+                router
+                    .get("/db")
+                    .handler(worldHandler::readRandomWorld)
+
+                router
+                    .get("/queries")
+                    .handler(worldHandler::readRandomWorlds)
+
+                router
+                    .get("/updates")
+                    .handler(worldHandler::updateRandomWorlds)
+
+                val server = vertx
+                    .createHttpServer(HTTP_SERVER_OPTIONS)
+                    .requestHandler(router)
+                    .exceptionHandler {
+                        if (it.isConnectionReset()) return@exceptionHandler
+                        logger.error(it) { "Exception in HttpServer" }
+                    }
+
+                server
+                    .listen()
+                    .onSuccess {
+                        logger.info { "HTTP server started on port 8080" }
+                        startPromise.complete()
+                    }
+                    .onFailure {
+                        logger.error(it) { "Failed to start" }
+                        startPromise.fail(it)
+                    }
+            }
+            .onFailure {
+                logger.error(it) { "Failed to start" }
+                startPromise.fail(it)
+            }
+    }
+
+    companion object : Logging {
+        private const val HTTP_SERVER_OPTIONS_RESOURCE = "http-server-options.json"
+        private const val PG_CONNECT_OPTIONS_RESOURCE = "pg-connect-options.json"
+
+        private val HTTP_SERVER_OPTIONS: HttpServerOptions by lazy {
+            val json = JsonResource.of(HTTP_SERVER_OPTIONS_RESOURCE)
+            HttpServerOptions(json)
+        }
+
+        private val PG_CONNECT_OPTIONS: PgConnectOptions by lazy {
+            val json = JsonResource.of(PG_CONNECT_OPTIONS_RESOURCE)
+            PgConnectOptions(json)
+        }
+    }
+}

+ 7 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt

@@ -0,0 +1,7 @@
+package com.example.starter.db
+
+import io.vertx.pgclient.PgConnection
+
+abstract class AbstractRepository<T>(
+    protected val pool: Array<PgConnection>
+)

+ 23 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt

@@ -0,0 +1,23 @@
+package com.example.starter.db
+
+import com.example.starter.models.Fortune
+import com.example.starter.utils.mapToArray
+
+import io.vertx.core.Future
+import io.vertx.pgclient.PgConnection
+import io.vertx.sqlclient.Row
+
+class FortuneRepository(pool: Array<PgConnection>) : AbstractRepository<Fortune>(pool) {
+    private val selectFortuneQuery = this.pool[0].preparedQuery(SELECT_FORTUNE_SQL)
+
+    fun selectFortunes(): Future<Array<Fortune>> = selectFortuneQuery
+        .execute()
+        .map { it.mapToArray(FortuneRepository::map) }
+
+    companion object {
+        private const val SELECT_FORTUNE_SQL = "SELECT id, message FROM fortune"
+
+        @Suppress("NOTHING_TO_INLINE")
+        private inline fun map(row: Row): Fortune = Fortune(row.getInteger(0), row.getString(1))
+    }
+}

+ 84 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt

@@ -0,0 +1,84 @@
+package com.example.starter.db
+
+import com.example.starter.models.World
+import io.vertx.core.Future
+import io.vertx.core.Promise
+import io.vertx.pgclient.PgConnection
+import io.vertx.sqlclient.PreparedQuery
+import io.vertx.sqlclient.Row
+import io.vertx.sqlclient.RowSet
+import io.vertx.sqlclient.Tuple
+import io.vertx.sqlclient.impl.ArrayTuple
+import io.vertx.sqlclient.impl.SqlClientInternal
+import java.util.concurrent.ThreadLocalRandom
+import java.util.concurrent.atomic.AtomicInteger
+
+@Suppress("NOTHING_TO_INLINE")
+class WorldRepository(pool: Array<PgConnection>) : AbstractRepository<World>(pool) {
+    private val selectWorldQuery = this.pool[0].preparedQuery(SELECT_WORLD_SQL)
+    private val updateWorldQueries = generateQueries(this.pool[1])
+
+    fun selectRandomWorld(): Future<World> = selectWorldQuery
+        .execute(Tuple.of(randomWorld()))
+        .map { map(it.iterator().next()) }
+
+    fun selectRandomWorlds(numWorlds: Int): Future<Array<World>> {
+        val promise = Promise.promise<Array<World>>()
+        val arr = arrayOfNulls<World>(numWorlds)
+        val count = AtomicInteger(0)
+        (this.pool[0] as SqlClientInternal).group { c ->
+            repeat(numWorlds) {
+                c.preparedQuery(SELECT_WORLD_SQL).execute(Tuple.of(randomWorld())) { ar ->
+                    val index = count.getAndIncrement()
+                    arr[index] = map(ar.result().iterator().next())
+                    if (index == numWorlds - 1) {
+                        promise.complete(arr as Array<World>)
+                    }
+                }
+            }
+        }
+        return promise.future()
+    }
+
+    fun updateRandomWorlds(numWorlds: Int): Future<Array<World>> = selectRandomWorlds(numWorlds)
+        .flatMap { worlds ->
+            val params = ArrayTuple(worlds.size * 3)
+            worlds.forEach {
+                it.randomNumber = randomWorld()
+                params.addValue(it.id)
+                params.addValue(it.randomNumber)
+            }
+            worlds.forEach {
+                params.addValue(it.id)
+            }
+            updateWorldQueries[numWorlds - 1].execute(params).map { worlds }
+        }
+
+    companion object {
+        private const val SELECT_WORLD_SQL = "SELECT id, randomnumber FROM world WHERE id = $1"
+
+        private inline fun randomWorld(): Int = 1 + ThreadLocalRandom.current().nextInt(10000)
+        private inline fun map(row: Row): World = World(row.getInteger(0), row.getInteger(1))
+
+        private fun generateQueries(conn: PgConnection): Array<PreparedQuery<RowSet<Row>>> {
+            val arr = arrayOfNulls<PreparedQuery<RowSet<Row>>>(500)
+            for (num in 1..500) {
+                var paramIndex = 1
+                val sb = StringBuilder()
+                sb.append("UPDATE world SET randomnumber = CASE id ")
+                for (i in 1..num) {
+                    sb.append("WHEN \$$paramIndex THEN \$${paramIndex + 1} ")
+                    paramIndex += 2
+                }
+                sb.append("ELSE randomnumber END WHERE id IN (")
+                for (i in 1..num) {
+                    sb.append("\$$paramIndex,")
+                    paramIndex += 1
+                }
+                sb[sb.length - 1] = ')'
+                arr[num - 1] = conn.preparedQuery(sb.toString())
+            }
+            return arr as Array<PreparedQuery<RowSet<Row>>>
+        }
+    }
+}

+ 57 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt

@@ -0,0 +1,57 @@
+package com.example.starter.handlers
+
+import com.example.starter.utils.PeriodicDateResolver
+import io.vertx.core.AsyncResult
+import io.vertx.core.Handler
+import io.vertx.core.MultiMap
+import io.vertx.core.http.HttpHeaders
+import io.vertx.core.http.HttpServerResponse
+import io.vertx.ext.web.RoutingContext
+
+@Suppress("NOTHING_TO_INLINE")
+abstract class AbstractHandler {
+    protected companion object {
+        val NULL_HANDLER: Handler<AsyncResult<Void>>? = null
+
+        const val SOMETHING_WENT_WRONG = "Something went wrong"
+
+        // Headers
+        val SERVER: CharSequence = HttpHeaders.createOptimized("Vert.x-Web")
+        val APPLICATION_JSON: CharSequence = HttpHeaders.createOptimized("application/json")
+        val TEXT_PLAIN: CharSequence = HttpHeaders.createOptimized("text/plain")
+        val TEXT_HTML: CharSequence = HttpHeaders.createOptimized("text/html; charset=utf-8")
+
+        inline fun MultiMap.common(): MultiMap = this
+            .add(HttpHeaders.SERVER, SERVER)
+            .add(HttpHeaders.DATE, PeriodicDateResolver.current)
+
+        inline fun RoutingContext.json(): HttpServerResponse {
+            val response = this.response()
+            val headers = response.headers()
+            headers
+                .common()
+                .add(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON)
+            return response
+        }
+
+        inline fun RoutingContext.text(): HttpServerResponse {
+            val response = this.response()
+            val headers = response.headers()
+            headers
+                .common()
+                .add(HttpHeaders.CONTENT_TYPE, TEXT_PLAIN)
+            return response
+        }
+
+        inline fun RoutingContext.html(): HttpServerResponse {
+            val response = this.response()
+            val headers = response.headers()
+            headers
+                .common()
+                .add(HttpHeaders.CONTENT_TYPE, TEXT_HTML)
+            return response
+        }
+
+        inline fun RoutingContext.error(): Unit = this.text().end(SOMETHING_WENT_WRONG, NULL_HANDLER)
+    }
+}

+ 15 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt

@@ -0,0 +1,15 @@
+package com.example.starter.handlers
+
+import io.vertx.core.buffer.Buffer
+import io.vertx.ext.web.RoutingContext
+
+class DefaultHandler : AbstractHandler() {
+    fun plaintext(ctx: RoutingContext) {
+        ctx.text().end(MESSAGE_BUFFER, NULL_HANDLER)
+    }
+
+    companion object {
+        private const val MESSAGE = "Hello, World!"
+        private val MESSAGE_BUFFER = Buffer.buffer(MESSAGE, "UTF-8")
+    }
+}

+ 57 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt

@@ -0,0 +1,57 @@
+package com.example.starter.handlers
+
+import com.example.starter.db.FortuneRepository
+import com.example.starter.models.Fortune
+import htmlflow.HtmlFlow
+import htmlflow.HtmlView
+import io.vertx.ext.web.RoutingContext
+import org.apache.logging.log4j.kotlin.Logging
+
+class FortuneHandler(private val repository: FortuneRepository) : AbstractHandler() {
+    fun templateFortunes(ctx: RoutingContext) {
+        repository
+            .selectFortunes()
+            .onSuccess {
+                val updatedFortunes = it.plus(Fortune(0, "Additional fortune added at request time."))
+                updatedFortunes.sort()
+                ctx.html().end(TEMPLATE.render(updatedFortunes), NULL_HANDLER)
+            }
+            .onFailure {
+                logger.error(it) { SOMETHING_WENT_WRONG }
+                ctx.error()
+            }
+    }
+
+    companion object : Logging {
+        private val TEMPLATE: HtmlView<Any> = HtmlFlow
+            .view<Any> { page ->
+                page
+                    .html()
+                        .head()
+                            .title()
+                                .text("Fortunes")
+                            .`__`() // title
+                        .`__`() // head
+                        .body()
+                            .table()
+                                .tr()
+                                    .th().text("id").`__`()
+                                    .th().text("message").`__`()
+                                .`__`() // tr
+                                .dynamic<Array<Fortune>> { container, fortunes ->
+                                    fortunes.forEach {
+                                        container
+                                            .tr()
+                                                .td().text(it.id.toString()).`__`()
+                                                .td().text(it.message).`__`()
+                                            .`__`() // tr
+                                    }
+                                }
+                            .`__`() // table
+                        .`__`() // body
+                    .`__`() // html
+            }
+            .setIndented(false)
+            .threadSafe()
+    }
+}

+ 15 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt

@@ -0,0 +1,15 @@
+package com.example.starter.handlers
+
+import com.example.starter.models.Message
+import com.example.starter.utils.serialize
+import io.vertx.ext.web.RoutingContext
+
+class MessageHandler : AbstractHandler() {
+    fun readDefaultMessage(ctx: RoutingContext) {
+        ctx.json().end(DEFAULT_MESSAGE.serialize(), NULL_HANDLER)
+    }
+
+    companion object {
+        private val DEFAULT_MESSAGE = Message("Hello, World!")
+    }
+}

+ 56 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/WorldHandler.kt

@@ -0,0 +1,56 @@
+package com.example.starter.handlers
+
+import com.example.starter.db.WorldRepository
+import com.example.starter.utils.serialize
+import io.vertx.ext.web.RoutingContext
+import org.apache.logging.log4j.kotlin.Logging
+
+class WorldHandler(private val repository: WorldRepository) : AbstractHandler() {
+    fun readRandomWorld(ctx: RoutingContext) {
+        repository
+            .selectRandomWorld()
+            .onSuccess {
+                ctx.json().end(it.serialize(), NULL_HANDLER)
+            }
+            .onFailure {
+                logger.error(it) { SOMETHING_WENT_WRONG }
+                ctx.error()
+            }
+    }
+
+    fun readRandomWorlds(ctx: RoutingContext) {
+        val queries = ctx.queries()
+        repository
+            .selectRandomWorlds(queries)
+            .onSuccess {
+                ctx.json().end(it.serialize(), NULL_HANDLER)
+            }
+            .onFailure {
+                logger.error(it) { SOMETHING_WENT_WRONG }
+                ctx.error()
+            }
+    }
+
+    fun updateRandomWorlds(ctx: RoutingContext) {
+        val queries = ctx.queries()
+        repository
+            .updateRandomWorlds(queries)
+            .onSuccess {
+                ctx.json().end(it.serialize(), NULL_HANDLER)
+            }
+            .onFailure {
+                logger.error(it) { SOMETHING_WENT_WRONG }
+                ctx.error()
+            }
+    }
+
+    companion object : Logging {
+        private const val QUERIES_PARAM_NAME = "queries"
+
+        @Suppress("NOTHING_TO_INLINE")
+        private inline fun RoutingContext.queries(): Int {
+            val queriesParam = this.request().getParam(QUERIES_PARAM_NAME)
+            return queriesParam?.toIntOrNull()?.coerceIn(1, 500) ?: 1
+        }
+    }
+}

+ 362 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/BufferOutputStream.kt

@@ -0,0 +1,362 @@
+package com.example.starter.io
+
+import io.netty.buffer.ByteBuf
+import io.vertx.core.buffer.Buffer
+import io.vertx.core.json.JsonArray
+import io.vertx.core.json.JsonObject
+import java.io.IOException
+import java.io.OutputStream
+import java.nio.ByteBuffer
+import java.nio.charset.Charset
+
+class BufferOutputStream(initialSizeHint: Int = 0) : Buffer, OutputStream() {
+    private val buffer: Buffer = Buffer.buffer(initialSizeHint)
+
+    @Throws(IOException::class)
+    override fun write(b: Int) {
+        buffer.appendByte(b.toByte())
+    }
+
+    @Throws(IOException::class)
+    override fun write(bytes: ByteArray) {
+        buffer.appendBytes(bytes)
+    }
+
+    @Throws(IOException::class)
+    override fun write(bytes: ByteArray, offset: Int, len: Int) {
+        buffer.appendBytes(bytes, offset, len)
+    }
+
+    override fun toString(enc: String?): String {
+        return buffer.toString(enc)
+    }
+
+    override fun toString(enc: Charset?): String {
+        return buffer.toString(enc)
+    }
+
+    override fun writeToBuffer(other: Buffer?) {
+        buffer.writeToBuffer(other)
+    }
+
+    override fun readFromBuffer(pos: Int, other: Buffer?): Int {
+        return buffer.readFromBuffer(pos, other)
+    }
+
+    override fun copy(): Buffer {
+        return buffer.copy()
+    }
+
+    override fun toJsonObject(): JsonObject {
+        return buffer.toJsonObject()
+    }
+
+    override fun toJsonArray(): JsonArray {
+        return buffer.toJsonArray()
+    }
+
+    override fun getByte(pos: Int): Byte {
+        return buffer.getByte(pos)
+    }
+
+    override fun getUnsignedByte(pos: Int): Short {
+        return buffer.getUnsignedByte(pos)
+    }
+
+    override fun getInt(pos: Int): Int {
+        return buffer.getInt(pos)
+    }
+
+    override fun getIntLE(pos: Int): Int {
+        return buffer.getIntLE(pos)
+    }
+
+    override fun getUnsignedInt(pos: Int): Long {
+        return buffer.getUnsignedInt(pos)
+    }
+
+    override fun getUnsignedIntLE(pos: Int): Long {
+        return buffer.getUnsignedIntLE(pos)
+    }
+
+    override fun getLong(pos: Int): Long {
+        return buffer.getLong(pos)
+    }
+
+    override fun getLongLE(pos: Int): Long {
+        return buffer.getLongLE(pos)
+    }
+
+    override fun getDouble(pos: Int): Double {
+        return buffer.getDouble(pos)
+    }
+
+    override fun getFloat(pos: Int): Float {
+        return buffer.getFloat(pos)
+    }
+
+    override fun getShort(pos: Int): Short {
+        return buffer.getShort(pos)
+    }
+
+    override fun getShortLE(pos: Int): Short {
+        return buffer.getShortLE(pos)
+    }
+
+    override fun getUnsignedShort(pos: Int): Int {
+        return buffer.getUnsignedShort(pos)
+    }
+
+    override fun getUnsignedShortLE(pos: Int): Int {
+        return buffer.getUnsignedShortLE(pos)
+    }
+
+    override fun getMedium(pos: Int): Int {
+        return buffer.getMedium(pos)
+    }
+
+    override fun getMediumLE(pos: Int): Int {
+        return buffer.getMediumLE(pos)
+    }
+
+    override fun getUnsignedMedium(pos: Int): Int {
+        return buffer.getUnsignedMedium(pos)
+    }
+
+    override fun getUnsignedMediumLE(pos: Int): Int {
+        return buffer.getUnsignedMediumLE(pos)
+    }
+
+    override fun getBytes(): ByteArray {
+        return buffer.bytes
+    }
+
+    override fun getBytes(start: Int, end: Int): ByteArray {
+        return buffer.getBytes(start, end)
+    }
+
+    override fun getBytes(dst: ByteArray?): Buffer {
+        return buffer.getBytes(dst)
+    }
+
+    override fun getBytes(dst: ByteArray?, dstIndex: Int): Buffer {
+        return buffer.getBytes(dst, dstIndex)
+    }
+
+    override fun getBytes(start: Int, end: Int, dst: ByteArray?): Buffer {
+        return buffer.getBytes(start, end, dst)
+    }
+
+    override fun getBytes(start: Int, end: Int, dst: ByteArray?, dstIndex: Int): Buffer {
+        return buffer.getBytes(start, end, dst, dstIndex)
+    }
+
+    override fun getBuffer(start: Int, end: Int): Buffer {
+        return buffer.getBuffer(start, end)
+    }
+
+    override fun getString(start: Int, end: Int, enc: String?): String {
+        return buffer.getString(start, end, enc)
+    }
+
+    override fun getString(start: Int, end: Int): String {
+        return buffer.getString(start, end)
+    }
+
+    override fun appendBuffer(buff: Buffer?): Buffer {
+        return buffer.appendBuffer(buff)
+    }
+
+    override fun appendBuffer(buff: Buffer?, offset: Int, len: Int): Buffer {
+        return buffer.appendBuffer(buff, offset, len)
+    }
+
+    override fun appendBytes(bytes: ByteArray?): Buffer {
+        return buffer.appendBytes(bytes)
+    }
+
+    override fun appendBytes(bytes: ByteArray?, offset: Int, len: Int): Buffer {
+        return buffer.appendBytes(bytes, offset, len)
+    }
+
+    override fun appendByte(b: Byte): Buffer {
+        return buffer.appendByte(b)
+    }
+
+    override fun appendUnsignedByte(b: Short): Buffer {
+        return buffer.appendUnsignedByte(b)
+    }
+
+    override fun appendInt(i: Int): Buffer {
+        return buffer.appendInt(i)
+    }
+
+    override fun appendIntLE(i: Int): Buffer {
+        return buffer.appendIntLE(i)
+    }
+
+    override fun appendUnsignedInt(i: Long): Buffer {
+        return buffer.appendUnsignedInt(i)
+    }
+
+    override fun appendUnsignedIntLE(i: Long): Buffer {
+        return buffer.appendUnsignedIntLE(i)
+    }
+
+    override fun appendMedium(i: Int): Buffer {
+        return buffer.appendMedium(i)
+    }
+
+    override fun appendMediumLE(i: Int): Buffer {
+        return buffer.appendMediumLE(i)
+    }
+
+    override fun appendLong(l: Long): Buffer {
+        return buffer.appendLong(l)
+    }
+
+    override fun appendLongLE(l: Long): Buffer {
+        return buffer.appendLongLE(l)
+    }
+
+    override fun appendShort(s: Short): Buffer {
+        return buffer.appendShort(s)
+    }
+
+    override fun appendShortLE(s: Short): Buffer {
+        return buffer.appendShortLE(s)
+    }
+
+    override fun appendUnsignedShort(s: Int): Buffer {
+        return buffer.appendUnsignedShort(s)
+    }
+
+    override fun appendUnsignedShortLE(s: Int): Buffer {
+        return buffer.appendUnsignedShortLE(s)
+    }
+
+    override fun appendFloat(f: Float): Buffer {
+        return buffer.appendFloat(f)
+    }
+
+    override fun appendDouble(d: Double): Buffer {
+        return buffer.appendDouble(d)
+    }
+
+    override fun appendString(str: String?, enc: String?): Buffer {
+        return buffer.appendString(str, enc)
+    }
+
+    override fun appendString(str: String?): Buffer {
+        return buffer.appendString(str)
+    }
+
+    override fun setByte(pos: Int, b: Byte): Buffer {
+        return buffer.setByte(pos, b)
+    }
+
+    override fun setUnsignedByte(pos: Int, b: Short): Buffer {
+        return buffer.setUnsignedByte(pos, b)
+    }
+
+    override fun setInt(pos: Int, i: Int): Buffer {
+        return buffer.setInt(pos, i)
+    }
+
+    override fun setIntLE(pos: Int, i: Int): Buffer {
+        return buffer.setIntLE(pos, i)
+    }
+
+    override fun setUnsignedInt(pos: Int, i: Long): Buffer {
+        return buffer.setUnsignedInt(pos, i)
+    }
+
+    override fun setUnsignedIntLE(pos: Int, i: Long): Buffer {
+        return buffer.setUnsignedIntLE(pos, i)
+    }
+
+    override fun setMedium(pos: Int, i: Int): Buffer {
+        return buffer.setMedium(pos, i)
+    }
+
+    override fun setMediumLE(pos: Int, i: Int): Buffer {
+        return buffer.setMediumLE(pos, i)
+    }
+
+    override fun setLong(pos: Int, l: Long): Buffer {
+        return buffer.setLong(pos, l)
+    }
+
+    override fun setLongLE(pos: Int, l: Long): Buffer {
+        return buffer.setLongLE(pos, l)
+    }
+
+    override fun setDouble(pos: Int, d: Double): Buffer {
+        return buffer.setDouble(pos, d)
+    }
+
+    override fun setFloat(pos: Int, f: Float): Buffer {
+        return buffer.setFloat(pos, f)
+    }
+
+    override fun setShort(pos: Int, s: Short): Buffer {
+        return buffer.setShort(pos, s)
+    }
+
+    override fun setShortLE(pos: Int, s: Short): Buffer {
+        return buffer.setShortLE(pos, s)
+    }
+
+    override fun setUnsignedShort(pos: Int, s: Int): Buffer {
+        return buffer.setUnsignedShort(pos, s)
+    }
+
+    override fun setUnsignedShortLE(pos: Int, s: Int): Buffer {
+        return buffer.setUnsignedShortLE(pos, s)
+    }
+
+    override fun setBuffer(pos: Int, b: Buffer?): Buffer {
+        return buffer.setBuffer(pos, b)
+    }
+
+    override fun setBuffer(pos: Int, b: Buffer?, offset: Int, len: Int): Buffer {
+        return buffer.setBuffer(pos, b, offset, len)
+    }
+
+    override fun setBytes(pos: Int, b: ByteBuffer?): Buffer {
+        return buffer.setBytes(pos, b)
+    }
+
+    override fun setBytes(pos: Int, b: ByteArray?): Buffer {
+        return buffer.setBytes(pos, b)
+    }
+
+    override fun setBytes(pos: Int, b: ByteArray?, offset: Int, len: Int): Buffer {
+        return buffer.setBytes(pos, b, offset, len)
+    }
+
+    override fun setString(pos: Int, str: String?): Buffer {
+        return buffer.setString(pos, str)
+    }
+
+    override fun setString(pos: Int, str: String?, enc: String?): Buffer {
+        return buffer.setString(pos, str, enc)
+    }
+
+    override fun length(): Int {
+        return buffer.length()
+    }
+
+    override fun slice(): Buffer {
+        return buffer.slice()
+    }
+
+    override fun slice(start: Int, end: Int): Buffer {
+        return buffer.slice(start, end)
+    }
+
+    @Deprecated("Deprecated in Java")
+    override fun getByteBuf(): ByteBuf {
+        return buffer.byteBuf
+    }
+}

+ 15 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/io/JsonResource.kt

@@ -0,0 +1,15 @@
+package com.example.starter.io
+
+import io.vertx.core.json.JsonObject
+
+object JsonResource {
+    fun of(resource: String): JsonObject {
+        val classLoader = ClassLoader.getSystemClassLoader()
+        classLoader.getResourceAsStream(resource)?.use { input ->
+            val output = BufferOutputStream()
+            output.write(input.readAllBytes())
+            return output.toJsonObject()
+        }
+        throw IllegalStateException("$resource not found")
+    }
+}

+ 14 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt

@@ -0,0 +1,14 @@
+package com.example.starter.models
+
+import com.dslplatform.json.CompiledJson
+import com.dslplatform.json.JsonAttribute
+
+@CompiledJson
+class Fortune(
+    @JsonAttribute(nullable = false) val id: Int,
+    @JsonAttribute(nullable = false) val message: String
+) : Comparable<Fortune> {
+    override fun compareTo(other: Fortune): Int {
+        return message.compareTo(other.message)
+    }
+}

+ 7 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt

@@ -0,0 +1,7 @@
+package com.example.starter.models
+
+import com.dslplatform.json.CompiledJson
+import com.dslplatform.json.JsonAttribute
+
+@CompiledJson
+class Message(@JsonAttribute(nullable = false) val message: String)

+ 14 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt

@@ -0,0 +1,14 @@
+package com.example.starter.models
+
+import com.dslplatform.json.CompiledJson
+import com.dslplatform.json.JsonAttribute
+
+@CompiledJson
+class World(
+    @JsonAttribute(nullable = false) val id: Int,
+    @JsonAttribute(nullable = false) var randomNumber: Int
+) : Comparable<World> {
+    override fun compareTo(other: World): Int {
+        return id.compareTo(other.id)
+    }
+}

+ 14 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt

@@ -0,0 +1,14 @@
+package com.example.starter.utils
+
+import io.vertx.core.CompositeFuture
+import io.vertx.core.Future
+import java.util.concurrent.TimeUnit
+import kotlin.time.Duration
+
+inline fun <reified T> CompositeFuture.array(): Array<T> = Array(this.size()) { this.resultAt(it) }
+
+@Suppress("NOTHING_TO_INLINE")
+inline fun <R, T: Future<R>> T.block(duration: Duration): R = this
+    .toCompletionStage()
+    .toCompletableFuture()
+    .get(duration.inWholeMilliseconds, TimeUnit.MILLISECONDS)

+ 19 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt

@@ -0,0 +1,19 @@
+package com.example.starter.utils
+
+import com.dslplatform.json.DslJson
+import com.dslplatform.json.runtime.Settings
+import com.example.starter.io.BufferOutputStream
+import io.vertx.core.buffer.Buffer
+
+val DSL_JSON: DslJson<Any> = DslJson(
+    Settings.withRuntime<Any>()
+        .includeServiceLoader()
+        .useStringValuesCache(DslJson.SimpleStringCache())
+)
+
+@Suppress("NOTHING_TO_INLINE")
+inline fun <T> T.serialize(initialSizeHint: Int = 0): Buffer {
+    val output = BufferOutputStream(initialSizeHint)
+    DSL_JSON.serialize(this, output)
+    return output
+}

+ 16 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/PeriodicDateResolver.kt

@@ -0,0 +1,16 @@
+package com.example.starter.utils
+
+import io.vertx.core.Vertx
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
+
+object PeriodicDateResolver {
+    var current: String = next()
+
+    fun init(vertx: Vertx) {
+        vertx.setPeriodic(1000L) { current = next() }
+    }
+
+    @Suppress("NOTHING_TO_INLINE")
+    private inline fun next(): String = DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())
+}

+ 14 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt

@@ -0,0 +1,14 @@
+package com.example.starter.utils
+
+import io.vertx.sqlclient.Row
+import io.vertx.sqlclient.RowSet
+
+// This extension relies on the assumption the mapper never returns null, as it is defined. Otherwise,
+// we prevent the overhead from having to do another iteration over the loop for a `filterNotNull` check.
+inline fun <reified U> RowSet<Row>.mapToArray(mapper: (Row) -> U): Array<U> {
+    val arr = arrayOfNulls<U>(this.size())
+    val iterator = this.iterator()
+    var index = 0
+    while (iterator.hasNext()) arr[index++] = mapper(iterator.next())
+    return arr as Array<U>
+}

+ 12 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt

@@ -0,0 +1,12 @@
+package com.example.starter.utils
+
+import io.netty.channel.unix.Errors
+import io.netty.channel.unix.Errors.NativeIoException
+import java.net.SocketException
+
+const val CONNECTION_RESET_MESSAGE = "Connection reset"
+
+fun Throwable.isConnectionReset(): Boolean {
+    return (this is NativeIoException && this.expectedErr() == Errors.ERRNO_ECONNRESET_NEGATIVE)
+        || (this is SocketException && this.message == CONNECTION_RESET_MESSAGE)
+}

+ 6 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/http-server-options.json

@@ -0,0 +1,6 @@
+{
+  "port": 8080,
+  "tcpFastOpen": true,
+  "receiveBufferSize": 262144,
+  "sendBufferSize": 262144
+}

+ 13 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/log4j2.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="WARN">
+  <Appenders>
+    <Console name="Console" target="SYSTEM_OUT">
+      <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
+    </Console>
+  </Appenders>
+  <Loggers>
+    <Root level="info">
+      <AppenderRef ref="Console"/>
+    </Root>
+  </Loggers>
+</Configuration>

+ 15 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/pg-connect-options.json

@@ -0,0 +1,15 @@
+{
+  "user": "benchmarkdbuser",
+  "password": "benchmarkdbpass",
+  "host": "tfb-database",
+  "port": 5432,
+  "database": "hello_world",
+  "cachePreparedStatements": true,
+  "preparedStatementCacheMaxSize": 512,
+  "preparedStatementCacheSqlLimit": 2048,
+  "tcpKeepAlive": true,
+  "tcpFastOpen": true,
+  "pipeliningLimit": 100000,
+  "receiveBufferSize": 262144,
+  "sendBufferSize": 262144
+}

+ 37 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile

@@ -0,0 +1,37 @@
+FROM gradle:8.9-jdk21 as gradle
+
+WORKDIR /vertx-web-kotlin-dsljson
+
+COPY src src
+COPY build.gradle.kts build.gradle.kts
+COPY gradle.properties gradle.properties
+COPY settings.gradle.kts settings.gradle.kts
+
+RUN gradle shadowJar
+
+EXPOSE 8080
+
+CMD java \
+    -server \
+    -Xms2G \
+    -Xmx2G \
+    -XX:+AlwaysPreTouch \
+    -XX:+UseParallelGC \
+	-XX:InitialCodeCacheSize=512m \
+    -XX:ReservedCodeCacheSize=512m \
+    -XX:MaxInlineLevel=20 \
+    -XX:+UseNUMA \
+    -Dvertx.disableMetrics=true \
+    -Dvertx.disableH2c=true \
+    -Dvertx.disableWebsockets=true \
+    -Dvertx.flashPolicyHandler=false \
+    -Dvertx.threadChecks=false \
+    -Dvertx.disableContextTimings=true \
+    -Dvertx.disableTCCL=true \
+    -Dvertx.disableHttpHeadersValidation=true \
+    -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \
+    -Dio.netty.buffer.checkBounds=false \
+    -Dio.netty.buffer.checkAccessible=false \
+    -Dtfb.hasDB=true \
+    -jar \
+    build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar

+ 37 - 0
frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile

@@ -0,0 +1,37 @@
+FROM gradle:8.9-jdk21 as gradle
+
+WORKDIR /vertx-web-kotlin-dsljson
+
+COPY src src
+COPY build.gradle.kts build.gradle.kts
+COPY gradle.properties gradle.properties
+COPY settings.gradle.kts settings.gradle.kts
+
+RUN gradle shadowJar
+
+EXPOSE 8080
+
+CMD java \
+    -server \
+    -Xms2G \
+    -Xmx2G \
+    -XX:+AlwaysPreTouch \
+    -XX:+UseParallelGC \
+	-XX:InitialCodeCacheSize=512m \
+    -XX:ReservedCodeCacheSize=512m \
+    -XX:MaxInlineLevel=20 \
+    -XX:+UseNUMA \
+    -Dvertx.disableMetrics=true \
+    -Dvertx.disableH2c=true \
+    -Dvertx.disableWebsockets=true \
+    -Dvertx.flashPolicyHandler=false \
+    -Dvertx.threadChecks=false \
+    -Dvertx.disableContextTimings=true \
+    -Dvertx.disableTCCL=true \
+    -Dvertx.disableHttpHeadersValidation=true \
+    -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \
+    -Dio.netty.buffer.checkBounds=false \
+    -Dio.netty.buffer.checkAccessible=false \
+    -Dtfb.hasDB=false \
+    -jar \
+    build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar