diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json b/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json index d2bab14abb7..2b8ebd26c83 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json @@ -18,8 +18,7 @@ "database_os": "Linux", "display_name": "vertx-web-kotlin-coroutines", "notes": "", - "versus": "vertx-web", - "tags": ["broken"] + "versus": "vertx-web" }, "postgres": { "db_url": "/db", diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts index 584f6102956..973bf6d8116 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts @@ -1,34 +1,37 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile tasks.wrapper { distributionType = Wrapper.DistributionType.ALL } plugins { - kotlin("jvm") version "1.8.10" + kotlin("jvm") version "2.0.21" application id("nu.studer.rocker") version "3.0.4" - id("com.github.johnrengelman.shadow") version "7.1.2" + id("com.gradleup.shadow") version "8.3.4" } group = "io.vertx" -version = "4.3.8" +version = "4.3.8" // 4.5.10 is available, but this is not updated to be kept consistent with the "vert-web" portion repositories { mavenCentral() } dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") implementation(platform("io.vertx:vertx-stack-depchain:$version")) implementation("io.vertx:vertx-core") - implementation("com.fasterxml.jackson.module:jackson-module-blackbird:2.14.2") + implementation("com.fasterxml.jackson.module:jackson-module-blackbird:2.14.2") // 2.18.1 is available, but this is not updated to be kept consistent with the "vert-web" portion implementation("io.vertx:vertx-web") implementation("io.vertx:vertx-pg-client") implementation("io.vertx:vertx-web-templ-rocker") - implementation("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") + runtimeOnly("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") + // not used to make the project consistent with the "vert-web" portion + /* + runtimeOnly("io.vertx:vertx-io_uring-incubator") + runtimeOnly("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.25.Final:linux-x86_64") + */ implementation("io.vertx:vertx-lang-kotlin") implementation("io.vertx:vertx-lang-kotlin-coroutines") } @@ -38,14 +41,12 @@ rocker { create("main") { templateDir.set(file("src/main/resources")) optimize.set(true) - javaVersion.set("17") + javaVersion.set("17") // kept consistent with the "vert-web" portion } } } -tasks.withType { - compilerOptions.jvmTarget.set(JvmTarget.JVM_17) -} +kotlin.jvmToolchain(17) // kept consistent with the "vert-web" portion // content below copied from the project generated by the app generator diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa75..a4b76b9530d 100644 Binary files a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.jar and b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.jar differ diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.properties index 2b22d057a07..79eb9d003fe 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew old mode 100644 new mode 100755 index 65dcd68d65c..f5feea6d6b1 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# 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/. @@ -83,10 +85,9 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# 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"' +# 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 @@ -133,10 +134,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + 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. @@ -144,7 +148,7 @@ 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=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,11 +201,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# 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" \ diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat index 93e3f59f135..9d21a21834d 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat @@ -13,6 +13,8 @@ @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 ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +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 @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +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 diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines-postgres.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines-postgres.dockerfile index 0703722b599..dfcc87cb4bb 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines-postgres.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines-postgres.dockerfile @@ -1,10 +1,8 @@ -FROM gradle:7.6-jdk17 as gradle +FROM gradle:8.10.2-jdk17 as gradle WORKDIR /vertx-web-kotlin-coroutines -COPY gradle gradle COPY src src COPY build.gradle.kts build.gradle.kts COPY gradle.properties gradle.properties -COPY gradlew gradlew COPY settings.gradle.kts settings.gradle.kts RUN gradle shadowJar diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines.dockerfile index 5c9e6378404..dfcc87cb4bb 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:7.6-jdk17 as gradle +FROM gradle:8.10.2-jdk17 as gradle WORKDIR /vertx-web-kotlin-coroutines COPY src src COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/vertx-web-kotlinx/README.md b/frameworks/Kotlin/vertx-web-kotlinx/README.md index 6c1d6caa252..b9fe8d87eef 100755 --- a/frameworks/Kotlin/vertx-web-kotlinx/README.md +++ b/frameworks/Kotlin/vertx-web-kotlinx/README.md @@ -2,7 +2,7 @@ Vert.x-Web in Kotlin with request handling implemented as much with official kotlinx libraries as possible. -Code is written from scratch to be as concise as possible with common code extracted into common (possibly inline) functions. SQL client implementation details and JVM Options are adapted referring to [the vertx-web portion](../../Java/vertx-web) and [the vertx portion](../../Java/vertx). All requests are handled in coroutines and suspend `await`s are used instead of future compositions. Compared to [the vertx-web-kotlin-coroutines portion](../vertx-web-kotlin-coroutines), besides adopting the Kotlinx libraries, this project simplifies the code by using more built-in Coroutine functions and avoids mutability as much as possible. JSON serialization is implemented with kotlinx.serialization and Fortunes with kotlinx.html. The benchmark is run on the latest LTS version of JVM, 17. +Code is written from scratch to be as concise as possible with common code extracted into common (possibly inline) functions. SQL client implementation details and JVM Options are adapted referring to [the vertx-web portion](../../Java/vertx-web) and [the vertx portion](../../Java/vertx). All requests are handled in coroutines and suspend `await`s are used instead of future compositions. Compared to [the vertx-web-kotlin-coroutines portion](../vertx-web-kotlin-coroutines), besides adopting the Kotlinx libraries, this project simplifies the code by using more built-in Coroutine functions and avoids mutability as much as possible. JSON serialization is implemented with kotlinx.serialization and Fortunes with kotlinx.html. The benchmark is run on the latest LTS version of JVM, 21. ## Test Type Implementation Source Code @@ -27,6 +27,7 @@ The tests were run with: * [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) * [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) +* [kotlinx-io](https://github.com/Kotlin/kotlinx-io) * [kotlinx.html](https://github.com/Kotlin/kotlinx.html) ## Test URLs diff --git a/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts index 232eadaf821..2e0035ab3e7 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts @@ -1,12 +1,9 @@ -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - tasks.wrapper { distributionType = Wrapper.DistributionType.ALL } plugins { - val kotlinVersion = "1.8.10" + val kotlinVersion = "2.0.21" kotlin("jvm") version kotlinVersion kotlin("plugin.serialization") version kotlinVersion application @@ -16,7 +13,8 @@ repositories { mavenCentral() } -val vertxVersion = "4.3.8" +val vertxVersion = "4.5.10" +val kotlinxSerializationVersion = "1.7.3" dependencies { implementation(platform("io.vertx:vertx-stack-depchain:$vertxVersion")) implementation("io.vertx:vertx-web") @@ -24,15 +22,20 @@ dependencies { implementation("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") implementation("io.vertx:vertx-lang-kotlin") implementation("io.vertx:vertx-lang-kotlin-coroutines") + runtimeOnly("io.vertx:vertx-io_uring-incubator") + // This dependency has to be added for io_uring to work. + runtimeOnly("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.25.Final:linux-x86_64") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") - implementation("org.jetbrains.kotlinx:kotlinx-html:0.8.0") - //implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") -} + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") -tasks.withType { - compilerOptions.jvmTarget.set(JvmTarget.JVM_17) + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-io:$kotlinxSerializationVersion") + implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.5.4") + + implementation("org.jetbrains.kotlinx:kotlinx-html:0.11.0") + //implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") // the latest version is 0.6.1 } +kotlin.jvmToolchain(21) + application.mainClass.set("MainKt") diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar index ccebba7710d..a4b76b9530d 100644 Binary files a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar and b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar differ diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties index 284897427bc..79eb9d003fe 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradlew b/frameworks/Kotlin/vertx-web-kotlinx/gradlew index 79a61d421cc..f5feea6d6b1 100755 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradlew +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# 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/. @@ -83,10 +85,9 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# 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"' +# 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 @@ -133,10 +134,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + 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. @@ -144,7 +148,7 @@ 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=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,11 +201,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# 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" \ diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat b/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat index 93e3f59f135..9d21a21834d 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat @@ -13,6 +13,8 @@ @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 ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +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 @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +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 diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/KotlinxIo.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/KotlinxIo.kt new file mode 100644 index 00000000000..6427b91e85e --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/KotlinxIo.kt @@ -0,0 +1,47 @@ +import io.vertx.core.streams.WriteStream +import io.vertx.kotlin.coroutines.coAwait +import kotlinx.coroutines.runBlocking +import kotlinx.io.RawSink +import kotlinx.io.readByteArray +import io.vertx.core.buffer.Buffer as VertxBuffer +import kotlinx.io.Buffer as KotlinxIoBuffer + +@Suppress("NOTHING_TO_INLINE") +private inline fun Long.toIntOrThrow(): Int { + require(this in Int.MIN_VALUE.toLong()..Int.MAX_VALUE.toLong()) + return toInt() +} + +@JvmInline +value class VertxBufferWriteStreamRawSink(val writeStream: WriteStream) : RawSink { + override fun write(source: KotlinxIoBuffer, byteCount: Long) { + runBlocking { + writeStream.write(VertxBuffer.buffer(source.readByteArray(byteCount.toIntOrThrow()))).coAwait() + } + } + + override fun flush() {} + + override fun close() { + writeStream.end() + } +} + +// not used currently +fun WriteStream.toRawSink(): RawSink = + VertxBufferWriteStreamRawSink(this) + + +@JvmInline +value class VertxBufferRawSink(val vertxBuffer: VertxBuffer) : RawSink { + override fun write(source: KotlinxIoBuffer, byteCount: Long) { + vertxBuffer.appendBytes(source.readByteArray(byteCount.toIntOrThrow())) + } + + override fun flush() {} + + override fun close() {} +} + +fun VertxBuffer.toRawSink(): RawSink = + VertxBufferRawSink(this) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt index 75cbd79e3cd..987c22162b3 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt @@ -2,10 +2,10 @@ 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 io.vertx.kotlin.coroutines.await +import io.vertx.kotlin.coroutines.coAwait import java.util.logging.Logger -const val SERVER_NAME = "Vert.x-Web Kotlinx Benchmark" +const val SERVER_NAME = "Vert.x-Web Kotlinx Benchmark server" val logger = Logger.getLogger("Vert.x-Web Kotlinx Benchmark") suspend fun main(args: Array) { @@ -19,6 +19,6 @@ suspend fun main(args: Array) { it.printStackTrace() } vertx.deployVerticle({ MainVerticle(hasDb) }, deploymentOptionsOf(instances = CpuCoreSensor.availableProcessors())) - .await() + .coAwait() logger.info("$SERVER_NAME started.") } diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt index 9d16710709e..2bd701fa083 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt @@ -1,4 +1,5 @@ import io.netty.channel.unix.Errors.NativeIoException +import io.vertx.core.buffer.Buffer import io.vertx.core.http.HttpHeaders import io.vertx.core.http.HttpServer import io.vertx.core.http.HttpServerRequest @@ -7,39 +8,28 @@ import io.vertx.ext.web.Route import io.vertx.ext.web.Router import io.vertx.ext.web.RoutingContext import io.vertx.kotlin.core.http.httpServerOptionsOf +import io.vertx.kotlin.coroutines.CoroutineRouterSupport import io.vertx.kotlin.coroutines.CoroutineVerticle -import io.vertx.kotlin.coroutines.await +import io.vertx.kotlin.coroutines.coAwait import io.vertx.kotlin.pgclient.pgConnectOptionsOf 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 kotlinx.coroutines.* +import kotlinx.coroutines.Dispatchers import kotlinx.html.* import kotlinx.html.stream.appendHTML +import kotlinx.io.buffered +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.Serializable -import kotlinx.serialization.encodeToString +import kotlinx.serialization.SerializationStrategy import kotlinx.serialization.json.Json -import java.net.SocketException +import kotlinx.serialization.json.io.encodeToSink import java.time.ZonedDateTime import java.time.format.DateTimeFormatter -class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { - inline fun Route.checkedCoroutineHandlerUnconfined(crossinline requestHandler: suspend (RoutingContext) -> Unit): Route = - handler { ctx -> - /* Some conclusions from the Plaintext test results with trailing `await()`s: - 1. `launch { /*...*/ }` < `launch(start = CoroutineStart.UNDISPATCHED) { /*...*/ }` < `launch(Dispatchers.Unconfined) { /*...*/ }`. - 1. `launch { /*...*/ }` without `context` or `start` lead to `io.netty.channel.StacklessClosedChannelException` and `io.netty.channel.unix.Errors$NativeIoException: sendAddress(..) failed: Connection reset by peer`. */ - launch(Dispatchers.Unconfined) { - try { - requestHandler(ctx) - } catch (t: Throwable) { - ctx.fail(t) - } - } - } - +class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSupport { // `PgConnection`s as used in the "vertx" portion offers better performance than `PgPool`s. lateinit var pgConnection: PgConnection lateinit var date: String @@ -68,7 +58,7 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { cachePreparedStatements = true, pipeliningLimit = 100000 ) - ).await() + ).coAwait() selectWorldQuery = pgConnection.preparedQuery(SELECT_WORLD_SQL) selectFortuneQuery = pgConnection.preparedQuery(SELECT_FORTUNE_SQL) @@ -81,15 +71,19 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { .requestHandler(Router.router(vertx).apply { routes() }) .exceptionHandler { // wrk resets the connections when benchmarking is finished. - if ((it is NativeIoException && it.message == "recvAddress(..) failed: Connection reset by peer") - || (it is SocketException && it.message == "Connection reset") + if ( + // for epoll + /*(it is NativeIoException && it.message == "recvAddress(..) failed: Connection reset by peer") + || (it is SocketException && it.message == "Connection reset")*/ + // for io_uring + it is NativeIoException && it.message == "io_uring read(..) failed: Connection reset by peer" ) return@exceptionHandler logger.info("Exception in HttpServer: $it") it.printStackTrace() } - .listen().await() + .listen().coAwait() } @@ -110,14 +104,46 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { putHeader(HttpHeaders.CONTENT_TYPE, "application/json") } - inline fun Route.jsonResponseHandler(crossinline requestHandler: suspend (RoutingContext) -> @Serializable T) = - checkedCoroutineHandlerUnconfined { + + fun Route.coHandlerUnconfined(requestHandler: suspend (RoutingContext) -> Unit): Route = + /* Some conclusions from the Plaintext test results with trailing `await()`s: + 1. `launch { /*...*/ }` < `launch(start = CoroutineStart.UNDISPATCHED) { /*...*/ }` < `launch(Dispatchers.Unconfined) { /*...*/ }`. + 1. `launch { /*...*/ }` without `context` or `start` lead to `io.netty.channel.StacklessClosedChannelException` and `io.netty.channel.unix.Errors$NativeIoException: sendAddress(..) failed: Connection reset by peer`. */ + coHandler(Dispatchers.Unconfined, requestHandler) + + inline fun Route.jsonResponseCoHandler( + serializer: SerializationStrategy, + crossinline requestHandler: suspend (RoutingContext) -> @Serializable T + ) = + coHandlerUnconfined { it.response().run { putJsonResponseHeader() - end(Json.encodeToString(requestHandler(it)))/*.await()*/ + + /* + // approach 1 + end(Json.encodeToString(serializer, requestHandler(it)))/*.coAwait()*/ + */ + + /* + // approach 2 + // java.lang.IllegalStateException: You must set the Content-Length header to be the total size of the message body BEFORE sending any data if you are not using HTTP chunked encoding. + toRawSink().buffered().use { bufferedSink -> + @OptIn(ExperimentalSerializationApi::class) + Json.encodeToSink(serializer, requestHandler(it), bufferedSink) + } + */ + + // approach 3 + end(Buffer.buffer().apply { + toRawSink().buffered().use { bufferedSink -> + @OptIn(ExperimentalSerializationApi::class) + Json.encodeToSink(serializer, requestHandler(it), bufferedSink) + } + }) } } + suspend fun selectRandomWorlds(queries: Int): List { val rowSets = List(queries) { selectWorldQuery.execute(Tuple.of(randomIntBetween1And10000())) @@ -126,23 +152,23 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { } fun Router.routes() { - get("/json").jsonResponseHandler { + get("/json").jsonResponseCoHandler(Serializers.message) { jsonSerializationMessage } - get("/db").jsonResponseHandler { - val rowSet = selectWorldQuery.execute(Tuple.of(randomIntBetween1And10000())).await() + get("/db").jsonResponseCoHandler(Serializers.world) { + val rowSet = selectWorldQuery.execute(Tuple.of(randomIntBetween1And10000())).coAwait() rowSet.single().toWorld() } - get("/queries").jsonResponseHandler { + get("/queries").jsonResponseCoHandler(Serializers.worlds) { val queries = it.request().getQueries() selectRandomWorlds(queries) } - get("/fortunes").checkedCoroutineHandlerUnconfined { + get("/fortunes").coHandlerUnconfined { val fortunes = mutableListOf() - selectFortuneQuery.execute().await() + selectFortuneQuery.execute().coAwait() .mapTo(fortunes) { it.toFortune() } fortunes.add(Fortune(0, "Additional fortune added at request time.")) @@ -173,11 +199,11 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { it.response().run { putCommonHeaders() putHeader(HttpHeaders.CONTENT_TYPE, "text/html; charset=utf-8") - end(htmlString)/*.await()*/ + end(htmlString)/*.coAwait()*/ } } - get("/updates").jsonResponseHandler { + get("/updates").jsonResponseCoHandler(Serializers.worlds) { val queries = it.request().getQueries() val worlds = selectRandomWorlds(queries) val updatedWorlds = worlds.map { it.copy(randomNumber = randomIntBetween1And10000()) } @@ -185,7 +211,7 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { // Approach 1 // The updated worlds need to be sorted first to avoid deadlocks. updateWordQuery - .executeBatch(updatedWorlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) }).await() + .executeBatch(updatedWorlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) }).coAwait() /* // Approach 2, worse performance @@ -197,11 +223,11 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { updatedWorlds } - get("/plaintext").checkedCoroutineHandlerUnconfined { + get("/plaintext").coHandlerUnconfined { it.response().run { putCommonHeaders() putHeader(HttpHeaders.CONTENT_TYPE, "text/plain") - end("Hello, World!")/*.await()*/ + end("Hello, World!")/*.coAwait()*/ } } } diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt new file mode 100644 index 00000000000..c975fc07fdd --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt @@ -0,0 +1,7 @@ +import kotlinx.serialization.serializer + +object Serializers { + val message = serializer() + val world = serializer() + val worlds = serializer>() +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt index bb8d419d399..d6230fef7f7 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt @@ -1,6 +1,5 @@ -import io.vertx.core.CompositeFuture import io.vertx.core.Future -import io.vertx.kotlin.coroutines.await +import io.vertx.kotlin.coroutines.coAwait suspend fun List>.awaitAll(): List = - CompositeFuture.all(this).await().list() + Future.all(this).coAwait().list() diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile index 55c7c2c6803..17b43ebcb5c 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile @@ -1,12 +1,11 @@ -FROM gradle:8.0-jdk17 +FROM gradle:8.10.2-jdk21 WORKDIR /vertx-web-kotlinx COPY build.gradle.kts build.gradle.kts COPY settings.gradle.kts settings.gradle.kts COPY gradle.properties gradle.properties COPY src src -RUN gradle assembleDist -RUN tar -xf build/distributions/vertx-web-kotlinx-benchmark.tar +RUN gradle --no-daemon installDist EXPOSE 8080 @@ -25,4 +24,4 @@ CMD export JAVA_OPTS=" \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ " && \ - vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark true + build/install/vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark true diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile index 63d2d4a68ad..4bdc993707d 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile @@ -1,12 +1,11 @@ -FROM gradle:8.0-jdk17 +FROM gradle:8.10.2-jdk21 WORKDIR /vertx-web-kotlinx COPY build.gradle.kts build.gradle.kts COPY settings.gradle.kts settings.gradle.kts COPY gradle.properties gradle.properties COPY src src -RUN gradle assembleDist -RUN tar -xf build/distributions/vertx-web-kotlinx-benchmark.tar +RUN gradle --no-daemon installDist EXPOSE 8080 @@ -25,4 +24,4 @@ CMD export JAVA_OPTS=" \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ " && \ - vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark false + build/install/vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark false