Browse Source

[Ktor] Latest Ktor, serializer, html dsl versions (#9128)

* latest Ktor, serializer, html dsl versions

jvm runtime is now 17

Update README.md

modernized all ktor tests to jvm 17 and latest ktor

small pgclient memory optimizations

big cleanup, removed pg-reactive-client, since it's evolution is already being tested

a small memory optimization

* fixed obsolete config

* cleaned up legacy test
Ilya Nemtsev 1 year ago
parent
commit
03c1c5c283

+ 0 - 23
frameworks/Kotlin/ktor/benchmark_config.json

@@ -94,29 +94,6 @@
         "notes": "",
         "notes": "",
         "versus": "netty"
         "versus": "netty"
       },
       },
-      "reactivepg": {
-        "json_url": "/json",
-        "plaintext_url": "/plaintext",
-        "db_url": "/db",
-        "query_url": "/query/?queries=",
-        "fortune_url": "/fortunes",
-        "update_url": "/updates?queries=",
-        "port": 8080,
-        "approach": "Realistic",
-        "classification": "Fullstack",
-        "database": "Postgres",
-        "framework": "Ktor",
-        "language": "Kotlin",
-        "flavor": "None",
-        "orm": "Raw",
-        "platform": "None",
-        "webserver": "None",
-        "os": "Linux",
-        "database_os": "Linux",
-        "display_name": "Ktor-reactivepg",
-        "notes": "",
-        "versus": "netty"
-      },
       "pgclient": {
       "pgclient": {
         "plaintext_url": "/plaintext",
         "plaintext_url": "/plaintext",
         "json_url": "/json",
         "json_url": "/json",

+ 0 - 17
frameworks/Kotlin/ktor/config.toml

@@ -35,23 +35,6 @@ platform = "None"
 webserver = "None"
 webserver = "None"
 versus = "netty"
 versus = "netty"
 
 
-[reactivepg]
-urls.plaintext = "/plaintext"
-urls.json = "/json"
-urls.db = "/db"
-urls.query = "/query/?queries="
-urls.update = "/updates?queries="
-urls.fortune = "/fortunes"
-approach = "Realistic"
-classification = "Fullstack"
-database = "Postgres"
-database_os = "Linux"
-os = "Linux"
-orm = "Raw"
-platform = "None"
-webserver = "None"
-versus = "netty"
-
 [cio]
 [cio]
 urls.plaintext = "/plaintext"
 urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.json = "/json"

+ 0 - 41
frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle

@@ -1,41 +0,0 @@
-plugins {
-    id "java"
-    id "application"
-    id 'org.jetbrains.kotlin.jvm'
-    id 'kotlinx-serialization'
-    id 'com.github.johnrengelman.shadow' version '4.0.3'
-}
-
-group 'org.jetbrains.ktor'
-version '1.0-SNAPSHOT'
-
-mainClassName = "MainKt"
-
-repositories {
-    mavenCentral()
-    jcenter()
-    maven { url "https://kotlin.bintray.com/kotlinx" }
-}
-
-dependencies {
-    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
-    compile "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.9.1"
-    compile "io.ktor:ktor-server-netty:$ktor_version"
-    compile "io.ktor:ktor-html-builder:$ktor_version"
-    compile "com.github.jasync-sql:jasync-postgresql:0.9.39"
-    compile "io.reactiverse:reactive-pg-client:0.11.3"
-    compile 'io.vertx:vertx-lang-kotlin-coroutines:3.7.0'
-}
-
-compileKotlin {
-    kotlinOptions.jvmTarget = "1.8"
-}
-compileTestKotlin {
-    kotlinOptions.jvmTarget = "1.8"
-}
-
-shadowJar {
-    baseName = "bench"
-    classifier = null
-    version = null
-}

+ 36 - 0
frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts

@@ -0,0 +1,36 @@
+plugins {
+    application
+    kotlin("jvm") version "1.9.22"
+    kotlin("plugin.serialization") version "2.0.0"
+    id("com.github.johnrengelman.shadow") version "8.1.0"
+}
+
+group = "org.jetbrains.ktor"
+version = "1.0-SNAPSHOT"
+
+repositories {
+    mavenCentral()
+}
+
+application {
+    mainClass.set("MainKt")
+}
+
+val ktor_version = "2.3.12"
+val kotlinx_serialization_version = "1.6.3"
+val vertx_pg_client = "4.5.8"
+
+dependencies {
+    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinx_serialization_version")
+    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
+    implementation("io.ktor:ktor-server-netty:$ktor_version")
+    implementation("io.ktor:ktor-server-default-headers:$ktor_version")
+    implementation("io.ktor:ktor-server-html-builder:$ktor_version")
+    implementation("com.github.jasync-sql:jasync-postgresql:2.2.0")
+}
+
+tasks.shadowJar {
+    archiveBaseName.set("bench")
+    archiveClassifier.set("")
+    archiveVersion.set("")
+}

+ 2 - 2
frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties

@@ -1,4 +1,4 @@
 kotlin.code.style=official
 kotlin.code.style=official
 
 
-kotlin_version=1.3.31
-ktor_version=1.2.0
+kotlin_version=1.9.22
+ktor_version=2.3.12

+ 1 - 1
frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip

+ 41 - 77
frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/main.kt

@@ -1,28 +1,21 @@
 import com.github.jasync.sql.db.ConnectionPoolConfiguration
 import com.github.jasync.sql.db.ConnectionPoolConfiguration
+import com.github.jasync.sql.db.QueryResult
 import com.github.jasync.sql.db.SuspendingConnection
 import com.github.jasync.sql.db.SuspendingConnection
 import com.github.jasync.sql.db.asSuspending
 import com.github.jasync.sql.db.asSuspending
 import com.github.jasync.sql.db.postgresql.PostgreSQLConnectionBuilder
 import com.github.jasync.sql.db.postgresql.PostgreSQLConnectionBuilder
-import io.ktor.application.call
-import io.ktor.application.install
-import io.ktor.features.DefaultHeaders
-import io.ktor.html.Placeholder
-import io.ktor.html.Template
-import io.ktor.html.insert
-import io.ktor.html.respondHtmlTemplate
 import io.ktor.http.ContentType
 import io.ktor.http.ContentType
-import io.ktor.response.respondText
-import io.ktor.routing.get
-import io.ktor.routing.routing
+import io.ktor.server.application.*
 import io.ktor.server.engine.embeddedServer
 import io.ktor.server.engine.embeddedServer
+import io.ktor.server.html.*
 import io.ktor.server.netty.Netty
 import io.ktor.server.netty.Netty
-import io.reactiverse.kotlin.pgclient.getConnectionAwait
-import io.reactiverse.kotlin.pgclient.preparedBatchAwait
-import io.reactiverse.kotlin.pgclient.preparedQueryAwait
-import io.reactiverse.pgclient.*
+import io.ktor.server.plugins.defaultheaders.*
+import io.ktor.server.response.*
+import io.ktor.server.routing.*
+import kotlinx.coroutines.*
 import kotlinx.html.*
 import kotlinx.html.*
 import kotlinx.serialization.Serializable
 import kotlinx.serialization.Serializable
-import kotlinx.serialization.json.JSON
-import kotlinx.serialization.list
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.json.Json
 import java.lang.IllegalArgumentException
 import java.lang.IllegalArgumentException
 import kotlin.random.Random
 import kotlin.random.Random
 import kotlin.random.nextInt
 import kotlin.random.nextInt
@@ -44,73 +37,48 @@ interface Repository {
 }
 }
 
 
 class JasyncRepository() : Repository {
 class JasyncRepository() : Repository {
-    private val dbConfig: ConnectionPoolConfiguration
-    private val db: SuspendingConnection
-
-    init {
-        dbConfig = ConnectionPoolConfiguration(
-            "tfb-database",
-            database = "hello_world",
-            username = "benchmarkdbuser",
-            password = "benchmarkdbpass",
-            maxActiveConnections = 64
-        )
-        db = PostgreSQLConnectionBuilder.createConnectionPool(dbConfig).asSuspending
+    companion object {
+        const val WORLD_QUERY = "select id, randomNumber from world where id = ?"
+        const val FORTUNES_QUERY = "select id, message from fortune"
+        const val UPDATE_QUERY = "update world set randomNumber = ? where id = ?"
     }
     }
 
 
+    private val dbConfig: ConnectionPoolConfiguration = ConnectionPoolConfiguration(
+        "tfb-database",
+        database = "hello_world",
+        username = "benchmarkdbuser",
+        password = "benchmarkdbpass",
+        maxActiveConnections = 64
+    )
+    private val db: SuspendingConnection = PostgreSQLConnectionBuilder.createConnectionPool(dbConfig).asSuspending
+
     override suspend fun getWorld(): World {
     override suspend fun getWorld(): World {
         val worldId = rand.nextInt(1, 10000)
         val worldId = rand.nextInt(1, 10000)
-        val result = db.sendPreparedStatement("select id, randomNumber from world where id = ?", listOf(worldId))
+        val result = db.sendPreparedStatement(WORLD_QUERY, listOf(worldId))
         val row = result.rows.first()
         val row = result.rows.first()
         return World(row.getInt(0)!!, row.getInt(1)!!)
         return World(row.getInt(0)!!, row.getInt(1)!!)
     }
     }
 
 
     override suspend fun getFortunes(): List<Fortune> {
     override suspend fun getFortunes(): List<Fortune> {
-        val results = db.sendPreparedStatement("select id, message from fortune")
+        val results = db.sendPreparedStatement(FORTUNES_QUERY)
         return results.rows.map { Fortune(it.getInt(0)!!, it.getString(1)!!) }
         return results.rows.map { Fortune(it.getInt(0)!!, it.getString(1)!!) }
     }
     }
 
 
     override suspend fun updateWorlds(worlds: List<World>) {
     override suspend fun updateWorlds(worlds: List<World>) {
-        worlds.forEach { world ->
-            db.sendPreparedStatement(
-                "update world set randomNumber = ? where id = ?",
-                listOf(world.randomNumber, world.id)
-            )
-        }
-    }
-}
+        coroutineScope {
+            val jobs = ArrayList<Deferred<QueryResult>>(worlds.size)
+            worlds.forEach { world ->
+                val deferred = async(Dispatchers.IO) {
+                    db.sendPreparedStatement(
+                        UPDATE_QUERY,
+                        listOf(world.randomNumber, world.id)
+                    )
+                }
+                jobs.add(deferred)
+            }
 
 
-class ReactivePGRepository : Repository {
-    private val db: PgPool
-
-    init {
-        val poolOptions = PgPoolOptions()
-        poolOptions.apply {
-            host = "tfb-database"
-            database = "hello_world"
-            user = "benchmarkdbuser"
-            password = "benchmarkdbpass"
-            maxSize = 64
-            cachePreparedStatements = true
+            jobs.awaitAll()
         }
         }
-        db = PgClient.pool(poolOptions)
-    }
-
-    override suspend fun getFortunes(): List<Fortune> {
-        val results = db.preparedQueryAwait("select id, message from fortune")
-        return results.map { Fortune(it.getInteger(0), it.getString(1)) }
-    }
-
-    override suspend fun getWorld(): World {
-        val worldId = rand.nextInt(1, 10000)
-        val result = db.preparedQueryAwait("select id, randomNumber from world where id = $1", Tuple.of(worldId))
-        val row = result.first()
-        return World(row.getInteger(0), row.getInteger(1)!!)
-    }
-
-    override suspend fun updateWorlds(worlds: List<World>) {
-        val batch = worlds.map { Tuple.of(it.id, it.randomNumber) }
-        db.preparedBatchAwait("update world set randomNumber = $1 where id = $2", batch)
     }
     }
 }
 }
 
 
@@ -132,7 +100,7 @@ class MainTemplate : Template<HTML> {
     }
     }
 }
 }
 
 
-class FortuneTemplate(val fortunes: List<Fortune>, val main: MainTemplate = MainTemplate()) : Template<HTML> {
+class FortuneTemplate(private val fortunes: List<Fortune>, private val main: MainTemplate = MainTemplate()) : Template<HTML> {
     override fun HTML.apply() {
     override fun HTML.apply() {
         insert(main) {
         insert(main) {
             content {
             content {
@@ -156,13 +124,9 @@ class FortuneTemplate(val fortunes: List<Fortune>, val main: MainTemplate = Main
 fun main(args: Array<String>) {
 fun main(args: Array<String>) {
     val db = when(args.firstOrNull()) {
     val db = when(args.firstOrNull()) {
         "jasync-sql" -> JasyncRepository()
         "jasync-sql" -> JasyncRepository()
-        "reactive-pg" -> ReactivePGRepository()
         else -> throw IllegalArgumentException("Must specify a postgres client")
         else -> throw IllegalArgumentException("Must specify a postgres client")
     }
     }
 
 
-    val messageSerializer = Message.serializer()
-    val worldSerializer = World.serializer()
-
     val server = embeddedServer(Netty, 8080, configure = {
     val server = embeddedServer(Netty, 8080, configure = {
         shareWorkGroup = true
         shareWorkGroup = true
     }) {
     }) {
@@ -174,19 +138,19 @@ fun main(args: Array<String>) {
 
 
             get("/json") {
             get("/json") {
                 call.respondText(
                 call.respondText(
-                    JSON.stringify(messageSerializer, Message("Hello, World!")),
+                    Json.encodeToString(Message("Hello, World!")),
                     ContentType.Application.Json
                     ContentType.Application.Json
                 )
                 )
             }
             }
 
 
             get("/db") {
             get("/db") {
-                call.respondText(JSON.stringify(worldSerializer, db.getWorld()), ContentType.Application.Json)
+                call.respondText(Json.encodeToString(db.getWorld()), ContentType.Application.Json)
             }
             }
 
 
             get("/query/") {
             get("/query/") {
                 val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1
                 val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1
                 val worlds = (1..queries).map { db.getWorld() }
                 val worlds = (1..queries).map { db.getWorld() }
-                call.respondText(JSON.stringify(worldSerializer.list, worlds), ContentType.Application.Json)
+                call.respondText(Json.encodeToString(worlds), ContentType.Application.Json)
             }
             }
 
 
             get("/fortunes") {
             get("/fortunes") {
@@ -204,7 +168,7 @@ fun main(args: Array<String>) {
 
 
                 db.updateWorlds(newWorlds)
                 db.updateWorlds(newWorlds)
 
 
-                call.respondText(JSON.stringify(worldSerializer.list, newWorlds), ContentType.Application.Json)
+                call.respondText(Json.encodeToString(newWorlds), ContentType.Application.Json)
             }
             }
         }
         }
     }
     }

+ 2 - 2
frameworks/Kotlin/ktor/ktor-cio.dockerfile

@@ -1,10 +1,10 @@
-FROM maven:3.6.1-jdk-11-slim as maven
+FROM maven:3.9.7-amazoncorretto-17-debian as maven
 WORKDIR /ktor
 WORKDIR /ktor
 COPY ktor/pom.xml pom.xml
 COPY ktor/pom.xml pom.xml
 COPY ktor/src src
 COPY ktor/src src
 RUN mvn clean package -q
 RUN mvn clean package -q
 
 
-FROM openjdk:11.0.3-jdk-stretch
+FROM amazoncorretto:17.0.11-al2023-headless
 WORKDIR /ktor
 WORKDIR /ktor
 COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-cio-bundle.jar app.jar
 COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-cio-bundle.jar app.jar
 
 

+ 1 - 1
frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile

@@ -1,4 +1,4 @@
-FROM gradle:8.0.2-jdk11
+FROM gradle:jdk17
 
 
 WORKDIR /ktor-exposed
 WORKDIR /ktor-exposed
 COPY ktor-exposed/settings.gradle.kts settings.gradle.kts
 COPY ktor-exposed/settings.gradle.kts settings.gradle.kts

+ 1 - 1
frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile

@@ -1,4 +1,4 @@
-FROM gradle:8.0.2-jdk11
+FROM gradle:jdk17
 
 
 WORKDIR /ktor-exposed
 WORKDIR /ktor-exposed
 COPY ktor-exposed/settings.gradle.kts settings.gradle.kts
 COPY ktor-exposed/settings.gradle.kts settings.gradle.kts

+ 5 - 5
frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts

@@ -1,7 +1,7 @@
 plugins {
 plugins {
-    kotlin("jvm") version "1.8.10"
-    kotlin("plugin.serialization") version "1.8.10"
     application
     application
+    kotlin("jvm") version "1.9.22"
+    kotlin("plugin.serialization") version "2.0.0"
     id("com.github.johnrengelman.shadow") version "8.1.0"
     id("com.github.johnrengelman.shadow") version "8.1.0"
 }
 }
 
 
@@ -9,9 +9,9 @@ repositories {
     mavenCentral()
     mavenCentral()
 }
 }
 
 
-val ktorVersion = "2.2.3"
-val kotlinxSerializationVersion = "1.5.0"
-val exposedVersion = "0.41.1"
+val ktorVersion = "2.3.12"
+val kotlinxSerializationVersion = "1.6.3"
+val exposedVersion = "0.52.0"
 
 
 dependencies {
 dependencies {
     implementation("io.ktor:ktor-server-core:$ktorVersion")
     implementation("io.ktor:ktor-server-core:$ktorVersion")

+ 2 - 2
frameworks/Kotlin/ktor/ktor-jasync.dockerfile

@@ -1,7 +1,7 @@
-FROM openjdk:11.0.3-jdk-stretch
+FROM maven:3.9.7-amazoncorretto-17-debian
 WORKDIR /app
 WORKDIR /app
 COPY ktor-asyncdb/gradle gradle
 COPY ktor-asyncdb/gradle gradle
-COPY ktor-asyncdb/build.gradle build.gradle
+COPY ktor-asyncdb/build.gradle.kts build.gradle.kts
 COPY ktor-asyncdb/gradle.properties gradle.properties
 COPY ktor-asyncdb/gradle.properties gradle.properties
 COPY ktor-asyncdb/gradlew gradlew
 COPY ktor-asyncdb/gradlew gradlew
 COPY ktor-asyncdb/settings.gradle settings.gradle
 COPY ktor-asyncdb/settings.gradle settings.gradle

+ 2 - 2
frameworks/Kotlin/ktor/ktor-jetty.dockerfile

@@ -1,10 +1,10 @@
-FROM maven:3.6.1-jdk-11-slim as maven
+FROM maven:3.9.7-amazoncorretto-17-debian as maven
 WORKDIR /ktor
 WORKDIR /ktor
 COPY ktor/pom.xml pom.xml
 COPY ktor/pom.xml pom.xml
 COPY ktor/src src
 COPY ktor/src src
 RUN mvn clean package -q
 RUN mvn clean package -q
 
 
-FROM openjdk:11.0.3-jdk-stretch
+FROM amazoncorretto:17.0.11-al2023-headless
 WORKDIR /ktor
 WORKDIR /ktor
 COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-jetty-bundle.jar app.jar
 COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-jetty-bundle.jar app.jar
 
 

+ 2 - 2
frameworks/Kotlin/ktor/ktor-pgclient.dockerfile

@@ -1,4 +1,4 @@
-FROM openjdk:11.0.3-jdk-stretch as build
+FROM maven:3.9.7-amazoncorretto-17-debian as build
 WORKDIR /app
 WORKDIR /app
 COPY ktor-pgclient/gradle gradle
 COPY ktor-pgclient/gradle gradle
 COPY ktor-pgclient/build.gradle.kts build.gradle.kts
 COPY ktor-pgclient/build.gradle.kts build.gradle.kts
@@ -6,7 +6,7 @@ COPY ktor-pgclient/gradlew gradlew
 COPY ktor-pgclient/src src
 COPY ktor-pgclient/src src
 RUN /app/gradlew --no-daemon shadowJar
 RUN /app/gradlew --no-daemon shadowJar
 
 
-FROM openjdk:11.0.3-jdk-slim
+FROM amazoncorretto:17.0.11-al2023-headless
 WORKDIR /app
 WORKDIR /app
 COPY --from=build /app/build/libs/ktor-pgclient.jar ktor-pgclient.jar
 COPY --from=build /app/build/libs/ktor-pgclient.jar ktor-pgclient.jar
 
 

+ 13 - 12
frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts

@@ -1,8 +1,8 @@
 plugins {
 plugins {
     application
     application
-    kotlin("jvm") version "1.6.10"
-    id("org.jetbrains.kotlin.plugin.serialization") version "1.6.21"
-    id("com.github.johnrengelman.shadow") version "7.1.2"
+    kotlin("jvm") version "1.9.22"
+    kotlin("plugin.serialization") version "2.0.0"
+    id("com.github.johnrengelman.shadow") version "8.1.0"
 }
 }
 
 
 group = "org.jetbrains.ktor"
 group = "org.jetbrains.ktor"
@@ -16,19 +16,20 @@ application {
     mainClass.set("MainKt")
     mainClass.set("MainKt")
 }
 }
 
 
+val ktor_version = "2.3.12"
+
 dependencies {
 dependencies {
-    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
-    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2")
-    implementation("io.ktor:ktor-server-netty:2.0.1")
-    implementation("io.ktor:ktor-server-html-builder-jvm:2.0.1")
-    implementation("io.ktor:ktor-server-default-headers-jvm:2.0.1")
-    implementation("io.vertx:vertx-pg-client:4.2.3")
-    implementation("io.vertx:vertx-lang-kotlin:4.2.3")
-    implementation("io.vertx:vertx-lang-kotlin-coroutines:4.2.3")
+    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
+    implementation("io.ktor:ktor-server-netty:$ktor_version")
+    implementation("io.ktor:ktor-server-html-builder-jvm:$ktor_version")
+    implementation("io.ktor:ktor-server-default-headers-jvm:$ktor_version")
+    implementation("io.vertx:vertx-pg-client:4.5.8")
+    implementation("io.vertx:vertx-lang-kotlin:4.5.8")
+    implementation("io.vertx:vertx-lang-kotlin-coroutines:4.5.8")
 }
 }
 
 
 tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
 tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
-    kotlinOptions.jvmTarget = "11"
+    kotlinOptions.jvmTarget = "17"
 }
 }
 
 
 tasks.shadowJar {
 tasks.shadowJar {

+ 1 - 1
frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties

@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
 zipStorePath=wrapper/dists

+ 19 - 9
frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt

@@ -7,6 +7,8 @@ import io.ktor.server.plugins.defaultheaders.*
 import io.ktor.server.response.*
 import io.ktor.server.response.*
 import io.ktor.server.routing.*
 import io.ktor.server.routing.*
 import io.vertx.kotlin.coroutines.await
 import io.vertx.kotlin.coroutines.await
+import io.vertx.kotlin.coroutines.coAwait
+import io.vertx.pgclient.PgBuilder
 import io.vertx.pgclient.PgConnectOptions
 import io.vertx.pgclient.PgConnectOptions
 import io.vertx.pgclient.PgPool
 import io.vertx.pgclient.PgPool
 import io.vertx.sqlclient.PoolOptions
 import io.vertx.sqlclient.PoolOptions
@@ -35,6 +37,12 @@ interface Repository {
 }
 }
 
 
 class PgclientRepository : Repository {
 class PgclientRepository : Repository {
+    companion object {
+        private const val FORTUNES_QUERY = "select id, message from FORTUNE"
+        private const val SELECT_WORLD_QUERY = "SELECT id, randomnumber from WORLD where id=$1"
+        private const val UPDATE_WORLD_QUERY = "UPDATE WORLD SET randomnumber=$1 WHERE id=$2"
+    }
+
     private val connectOptions =
     private val connectOptions =
         PgConnectOptions().apply {
         PgConnectOptions().apply {
             port = 5432
             port = 5432
@@ -47,21 +55,23 @@ class PgclientRepository : Repository {
         }
         }
 
 
     private val poolOptions = PoolOptions()
     private val poolOptions = PoolOptions()
-    private val client = ThreadLocal.withInitial { PgPool.client(connectOptions, poolOptions) }
-    private fun client() = client.get()
+    private val client = PgBuilder.client()
+        .with(poolOptions)
+        .connectingTo(connectOptions)
+        .build()
 
 
     override suspend fun getFortunes(): List<Fortune> {
     override suspend fun getFortunes(): List<Fortune> {
-        val results = client().preparedQuery("select id, message from fortune").execute().await()
+        val results = client.preparedQuery(FORTUNES_QUERY).execute().coAwait()
         return results.map { Fortune(it.getInteger(0), it.getString(1)) }
         return results.map { Fortune(it.getInteger(0), it.getString(1)) }
     }
     }
 
 
     override suspend fun getWorld(): World {
     override suspend fun getWorld(): World {
         val worldId = rand.nextInt(1, 10001)
         val worldId = rand.nextInt(1, 10001)
         val result =
         val result =
-            client()
-                .preparedQuery("select id, randomNumber from world where id = $1")
+            client
+                .preparedQuery(SELECT_WORLD_QUERY)
                 .execute(Tuple.of(worldId))
                 .execute(Tuple.of(worldId))
-                .await()
+                .coAwait()
         val row = result.first()
         val row = result.first()
         return World(row.getInteger(0), row.getInteger(1)!!)
         return World(row.getInteger(0), row.getInteger(1)!!)
     }
     }
@@ -69,10 +79,10 @@ class PgclientRepository : Repository {
     override suspend fun updateWorlds(worlds: List<World>) {
     override suspend fun updateWorlds(worlds: List<World>) {
         // Worlds should be sorted before being batch-updated with to avoid data race and deadlocks.
         // Worlds should be sorted before being batch-updated with to avoid data race and deadlocks.
         val batch = worlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) }
         val batch = worlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) }
-        client()
-            .preparedQuery("update world set randomNumber = $1 where id = $2")
+        client
+            .preparedQuery(UPDATE_WORLD_QUERY)
             .executeBatch(batch)
             .executeBatch(batch)
-            .await()
+            .coAwait()
     }
     }
 }
 }
 
 

+ 0 - 13
frameworks/Kotlin/ktor/ktor-reactivepg.dockerfile

@@ -1,13 +0,0 @@
-FROM openjdk:11.0.3-jdk-stretch
-WORKDIR /app
-COPY ktor-asyncdb/gradle gradle
-COPY ktor-asyncdb/build.gradle build.gradle
-COPY ktor-asyncdb/gradle.properties gradle.properties
-COPY ktor-asyncdb/gradlew gradlew
-COPY ktor-asyncdb/settings.gradle settings.gradle
-COPY ktor-asyncdb/src src
-RUN /app/gradlew --no-daemon shadowJar
-
-EXPOSE 9090
-
-CMD ["java", "-server", "-XX:+UseParallelGC", "-Xms2G","-Xmx2G", "-jar", "/app/build/libs/bench.jar", "reactive-pg"]

+ 3 - 3
frameworks/Kotlin/ktor/ktor.dockerfile

@@ -1,13 +1,13 @@
-FROM maven:3.6.1-jdk-11-slim as maven
+FROM maven:3.9.7-amazoncorretto-17-debian as maven
 WORKDIR /ktor
 WORKDIR /ktor
 COPY ktor/pom.xml pom.xml
 COPY ktor/pom.xml pom.xml
 COPY ktor/src src
 COPY ktor/src src
 RUN mvn clean package -q
 RUN mvn clean package -q
 
 
-FROM openjdk:11.0.3-jdk-stretch
+FROM amazoncorretto:17.0.11-al2023-headless
 WORKDIR /ktor
 WORKDIR /ktor
 COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar
 COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar
 
 
 EXPOSE 9090
 EXPOSE 9090
 
 
-CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "app.jar"]
+CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"]

+ 2 - 2
frameworks/Kotlin/ktor/ktor/README.md

@@ -5,13 +5,13 @@ More information is available at [ktor.io](http://ktor.io).
 
 
 # Setup
 # Setup
 
 
-* Java 8
+* Java 17
 * MySQL server
 * MySQL server
 
 
 # Requirements
 # Requirements
 
 
 * Maven 3
 * Maven 3
-* JDK 8
+* JDK 17
 * Kotlin
 * Kotlin
 * ktor
 * ktor
 * netty 
 * netty 

+ 7 - 12
frameworks/Kotlin/ktor/ktor/pom.xml

@@ -12,10 +12,10 @@
     <name>org.jetbrains.ktor tech-empower-framework-benchmark</name>
     <name>org.jetbrains.ktor tech-empower-framework-benchmark</name>
 
 
     <properties>
     <properties>
-        <kotlin.version>1.6.21</kotlin.version>
-        <ktor.version>2.0.1</ktor.version>
-        <serialization.version>1.3.2</serialization.version>
-        <kotlinx.html.version>0.7.3</kotlinx.html.version>
+        <kotlin.version>1.9.22</kotlin.version>
+        <ktor.version>2.3.11</ktor.version>
+        <serialization.version>1.6.3</serialization.version>
+        <kotlinx.html.version>0.11.0</kotlinx.html.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <hikaricp.version>5.0.0</hikaricp.version>
         <hikaricp.version>5.0.0</hikaricp.version>
         <logback.version>1.2.13</logback.version>
         <logback.version>1.2.13</logback.version>
@@ -24,11 +24,6 @@
     </properties>
     </properties>
 
 
     <dependencies>
     <dependencies>
-        <dependency>
-            <groupId>org.jetbrains.kotlin</groupId>
-            <artifactId>kotlin-stdlib-jdk8</artifactId>
-            <version>${kotlin.version}</version>
-        </dependency>
         <dependency>
         <dependency>
             <groupId>org.jetbrains.kotlin</groupId>
             <groupId>org.jetbrains.kotlin</groupId>
             <artifactId>kotlin-reflect</artifactId>
             <artifactId>kotlin-reflect</artifactId>
@@ -85,17 +80,17 @@
         <dependency>
         <dependency>
             <groupId>io.ktor</groupId>
             <groupId>io.ktor</groupId>
             <artifactId>ktor-server-netty-jvm</artifactId>
             <artifactId>ktor-server-netty-jvm</artifactId>
-            <version>2.0.0</version>
+            <version>${ktor.version}</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>io.ktor</groupId>
             <groupId>io.ktor</groupId>
             <artifactId>ktor-server-jetty-jvm</artifactId>
             <artifactId>ktor-server-jetty-jvm</artifactId>
-            <version>2.0.0</version>
+            <version>${ktor.version}</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>io.ktor</groupId>
             <groupId>io.ktor</groupId>
             <artifactId>ktor-server-cio-jvm</artifactId>
             <artifactId>ktor-server-cio-jvm</artifactId>
-            <version>2.0.0</version>
+            <version>${ktor.version}</version>
         </dependency>
         </dependency>
     </dependencies>
     </dependencies>
 
 

+ 16 - 7
frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt

@@ -9,12 +9,14 @@ import io.ktor.server.html.*
 import io.ktor.server.plugins.defaultheaders.*
 import io.ktor.server.plugins.defaultheaders.*
 import io.ktor.server.response.*
 import io.ktor.server.response.*
 import io.ktor.server.routing.*
 import io.ktor.server.routing.*
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
+import kotlinx.coroutines.*
 import kotlinx.html.*
 import kotlinx.html.*
 import kotlinx.serialization.Serializable
 import kotlinx.serialization.Serializable
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
 import kotlinx.serialization.json.Json
+import org.jetbrains.ktor.benchmarks.Constants.FORTUNES_QUERY
+import org.jetbrains.ktor.benchmarks.Constants.UPDATE_QUERY
+import org.jetbrains.ktor.benchmarks.Constants.WORLD_QUERY
 import java.sql.Connection
 import java.sql.Connection
 import java.util.concurrent.ThreadLocalRandom
 import java.util.concurrent.ThreadLocalRandom
 
 
@@ -30,7 +32,7 @@ data class Fortune(val id: Int, var message: String)
 fun Application.main() {
 fun Application.main() {
     val dbRows = 10000
     val dbRows = 10000
     val poolSize = 48
     val poolSize = 48
-    val pool by lazy { HikariDataSource(HikariConfig().apply { configurePostgres(poolSize) }) }
+    val pool = HikariDataSource(HikariConfig().apply { configurePostgres(poolSize) })
     val databaseDispatcher = Dispatchers.IO
     val databaseDispatcher = Dispatchers.IO
 
 
     install(DefaultHeaders)
     install(DefaultHeaders)
@@ -51,7 +53,7 @@ fun Application.main() {
 
 
             val world = withContext(databaseDispatcher) {
             val world = withContext(databaseDispatcher) {
                 pool.connection.use { connection ->
                 pool.connection.use { connection ->
-                    connection.prepareStatement("SELECT id, randomNumber FROM World WHERE id = ?").use { statement ->
+                    connection.prepareStatement(WORLD_QUERY).use { statement ->
                         statement.setInt(1, random.nextInt(dbRows) + 1)
                         statement.setInt(1, random.nextInt(dbRows) + 1)
 
 
                         statement.executeQuery().use { rs ->
                         statement.executeQuery().use { rs ->
@@ -67,7 +69,7 @@ fun Application.main() {
 
 
         fun Connection.selectWorlds(queries: Int, random: ThreadLocalRandom): List<World> {
         fun Connection.selectWorlds(queries: Int, random: ThreadLocalRandom): List<World> {
             val result = ArrayList<World>(queries)
             val result = ArrayList<World>(queries)
-            prepareStatement("SELECT id, randomNumber FROM World WHERE id = ?").use { statement ->
+            prepareStatement(WORLD_QUERY).use { statement ->
                 repeat(queries) {
                 repeat(queries) {
                     statement.setInt(1, random.nextInt(dbRows) + 1)
                     statement.setInt(1, random.nextInt(dbRows) + 1)
 
 
@@ -96,7 +98,7 @@ fun Application.main() {
             val result = mutableListOf<Fortune>()
             val result = mutableListOf<Fortune>()
             withContext(databaseDispatcher) {
             withContext(databaseDispatcher) {
                 pool.connection.use { connection ->
                 pool.connection.use { connection ->
-                    connection.prepareStatement("SELECT id, message FROM fortune").use { statement ->
+                    connection.prepareStatement(FORTUNES_QUERY).use { statement ->
                         statement.executeQuery().use { rs ->
                         statement.executeQuery().use { rs ->
                             while (rs.next()) {
                             while (rs.next()) {
                                 result += Fortune(rs.getInt(1), rs.getString(2))
                                 result += Fortune(rs.getInt(1), rs.getString(2))
@@ -137,7 +139,7 @@ fun Application.main() {
 
 
                     result.forEach { it.randomNumber = random.nextInt(dbRows) + 1 }
                     result.forEach { it.randomNumber = random.nextInt(dbRows) + 1 }
 
 
-                    connection.prepareStatement("UPDATE World SET randomNumber = ? WHERE id = ?")
+                    connection.prepareStatement(UPDATE_QUERY)
                         .use { updateStatement ->
                         .use { updateStatement ->
                             for ((id, randomNumber) in result) {
                             for ((id, randomNumber) in result) {
                                 updateStatement.setInt(1, randomNumber)
                                 updateStatement.setInt(1, randomNumber)
@@ -182,3 +184,10 @@ fun HikariConfig.configureMySql(poolSize: Int) {
 
 
 fun ApplicationCall.queries() =
 fun ApplicationCall.queries() =
     request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1
     request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1
+
+
+object Constants {
+    const val WORLD_QUERY = "SELECT id, randomNumber FROM World WHERE id = ?"
+    const val FORTUNES_QUERY = "SELECT id, message FROM fortune"
+    const val UPDATE_QUERY = "UPDATE World SET randomNumber = ? WHERE id = ?"
+}