Browse Source

Kotlin/http4k: Upgrade everything, add GraalVM and Loom builds (#7675)

* upgrade kotlin, gradle, http4k

* upgrade libraries, replace Jackson with Argo

* upgrade libraries, replace Jackson with Argo

* upgrade libraries, replace Jackson with Argo

* upgrade libraries, replace Jackson with Argo, introduce GraalVM

* update graalvm server to contain database routes

* remove cached queries from graal because it isn't supported

* rename graalvm jarfile

* adding in loom

* build custom gradle image for Java 19 builds

* rename dockerfile to be correct with the value set in the config file

* rename jetty dockerfile to be correct, fix config files as well

* switched port to 8080

* remove database tests for graalvm for the moment

* upgrade cache2k

* fixes for Cache2k API upgrades

* upgrade http4k

* repoint at port 9000, remove duplicate code from GraalVM

* fix graalvm configuration options

* added reflection config

* fixing graalvm reflection

* cleanup

* tweak implementation of cache population on update... much more efficient!

* added pbl resources and reflection config for fortune endpoint classes

* readded urls for graalvm

* tweak config for graalvm

* Introduce multiple database drivers (PGclient and Hikari) (#1)

Co-authored-by: albertlatacz <[email protected]>
David Denton 2 years ago
parent
commit
c2e68ac7bc
57 changed files with 820 additions and 199 deletions
  1. 2 0
      frameworks/Kotlin/http4k/.gitignore
  2. 1 0
      frameworks/Kotlin/http4k/.java-version
  3. 3 3
      frameworks/Kotlin/http4k/apache/build.gradle
  4. 6 7
      frameworks/Kotlin/http4k/apache/src/main/kotlin/Http4kApacheServer.kt
  5. 3 3
      frameworks/Kotlin/http4k/apache4/build.gradle
  6. 1 1
      frameworks/Kotlin/http4k/apache4/src/main/kotlin/Http4kApache4Server.kt
  7. 66 0
      frameworks/Kotlin/http4k/benchmark_config.json
  8. 3 3
      frameworks/Kotlin/http4k/build.gradle
  9. 54 0
      frameworks/Kotlin/http4k/config.toml
  10. 5 0
      frameworks/Kotlin/http4k/core-jdbc/build.gradle
  11. 94 0
      frameworks/Kotlin/http4k/core-jdbc/src/main/kotlin/PostgresDatabase.kt
  12. 4 0
      frameworks/Kotlin/http4k/core-pgclient/build.gradle
  13. 76 0
      frameworks/Kotlin/http4k/core-pgclient/src/main/kotlin/PostgresDatabase.kt
  14. 7 10
      frameworks/Kotlin/http4k/core/build.gradle
  15. 21 0
      frameworks/Kotlin/http4k/core/src/main/kotlin/AddHeaders.kt
  16. 6 100
      frameworks/Kotlin/http4k/core/src/main/kotlin/Database.kt
  17. 1 1
      frameworks/Kotlin/http4k/core/src/main/kotlin/FortunesRoute.kt
  18. 3 21
      frameworks/Kotlin/http4k/core/src/main/kotlin/Http4kBenchmarkServer.kt
  19. 3 3
      frameworks/Kotlin/http4k/core/src/main/kotlin/JsonRoute.kt
  20. 2 2
      frameworks/Kotlin/http4k/core/src/main/kotlin/WorldRoutes.kt
  21. 21 0
      frameworks/Kotlin/http4k/graalvm/build.gradle
  22. 92 0
      frameworks/Kotlin/http4k/graalvm/config/reflect-config.json
  23. 9 0
      frameworks/Kotlin/http4k/graalvm/config/resource-config.json
  24. 10 0
      frameworks/Kotlin/http4k/graalvm/src/main/kotlin/http4k/Http4kGraalVMBenchmarkServer.kt
  25. 4 2
      frameworks/Kotlin/http4k/http4k-apache.dockerfile
  26. 4 2
      frameworks/Kotlin/http4k/http4k-apache4.dockerfile
  27. 33 0
      frameworks/Kotlin/http4k/http4k-graalvm.dockerfile
  28. 4 2
      frameworks/Kotlin/http4k/http4k-jetty.dockerfile
  29. 49 0
      frameworks/Kotlin/http4k/http4k-jettyloom-jdbc.dockerfile
  30. 49 0
      frameworks/Kotlin/http4k/http4k-jettyloom-pgclient.dockerfile
  31. 4 2
      frameworks/Kotlin/http4k/http4k-ktorcio.dockerfile
  32. 4 2
      frameworks/Kotlin/http4k/http4k-ktornetty.dockerfile
  33. 4 2
      frameworks/Kotlin/http4k/http4k-netty.dockerfile
  34. 4 2
      frameworks/Kotlin/http4k/http4k-ratpack.dockerfile
  35. 4 2
      frameworks/Kotlin/http4k/http4k-undertow.dockerfile
  36. 4 2
      frameworks/Kotlin/http4k/http4k.dockerfile
  37. 3 3
      frameworks/Kotlin/http4k/jetty/build.gradle
  38. 1 1
      frameworks/Kotlin/http4k/jetty/src/main/kotlin/Http4kJettyServer.kt
  39. 14 0
      frameworks/Kotlin/http4k/jettyloom-jdbc/build.gradle
  40. 3 0
      frameworks/Kotlin/http4k/jettyloom-jdbc/src/main/kotlin/Http4kJettyLoomServer.kt
  41. 47 0
      frameworks/Kotlin/http4k/jettyloom-jdbc/src/main/kotlin/JettyLoom.kt
  42. 14 0
      frameworks/Kotlin/http4k/jettyloom-pgclient/build.gradle
  43. 3 0
      frameworks/Kotlin/http4k/jettyloom-pgclient/src/main/kotlin/Http4kJettyLoomServer.kt
  44. 47 0
      frameworks/Kotlin/http4k/jettyloom-pgclient/src/main/kotlin/JettyLoom.kt
  45. 3 3
      frameworks/Kotlin/http4k/ktorcio/build.gradle
  46. 1 1
      frameworks/Kotlin/http4k/ktorcio/src/main/kotlin/Http4kKtorCIOServer.kt
  47. 3 3
      frameworks/Kotlin/http4k/ktornetty/build.gradle
  48. 1 1
      frameworks/Kotlin/http4k/ktornetty/src/main/kotlin/Http4kKtorNettyServer.kt
  49. 3 3
      frameworks/Kotlin/http4k/netty/build.gradle
  50. 1 1
      frameworks/Kotlin/http4k/netty/src/main/kotlin/Http4kNettyServer.kt
  51. 3 3
      frameworks/Kotlin/http4k/ratpack/build.gradle
  52. 1 1
      frameworks/Kotlin/http4k/ratpack/src/main/kotlin/Http4kRatpackServer.kt
  53. 5 0
      frameworks/Kotlin/http4k/settings.gradle
  54. 2 2
      frameworks/Kotlin/http4k/sunhttp/build.gradle
  55. 1 1
      frameworks/Kotlin/http4k/sunhttp/src/main/kotlin/Http4kSunHttpServer.kt
  56. 3 3
      frameworks/Kotlin/http4k/undertow/build.gradle
  57. 1 1
      frameworks/Kotlin/http4k/undertow/src/main/kotlin/Http4kUndertowServer.kt

+ 2 - 0
frameworks/Kotlin/http4k/.gitignore

@@ -3,5 +3,7 @@ out
 docker
 .idea
 .gradle
+gradle/*
+gradle.properties
 /gradlew
 /gradlew.bat

+ 1 - 0
frameworks/Kotlin/http4k/.java-version

@@ -0,0 +1 @@
+19

+ 3 - 3
frameworks/Kotlin/http4k/apache/build.gradle

@@ -1,6 +1,6 @@
 dependencies {
-    api project(":core")
-    api "org.http4k:http4k-server-apache:$http4k_version"
+    api(project(":core-jdbc"))
+    api("org.http4k:http4k-server-apache:$http4k_version")
 }
 
 apply plugin: 'application'
@@ -8,7 +8,7 @@ mainClassName = "Http4kApacheServerKt"
 apply plugin: 'com.github.johnrengelman.shadow'
 
 shadowJar {
-    baseName = "http4k-$project.name-benchmark"
+    baseName = "http4k-benchmark"
     classifier = null
     version = null
     mergeServiceFiles()

+ 6 - 7
frameworks/Kotlin/http4k/apache/src/main/kotlin/Http4kApacheServer.kt

@@ -6,15 +6,14 @@ import org.http4k.server.Http4kServer
 import org.http4k.server.ServerConfig
 
 fun main() {
-    /**
-     * we need a custom config here because of how virtual hosting is required in the TFB
-     * environment. Normally we would just call the inbuilt ApacheServer(9000) function
-     */
-    val config = TfbApacheServer(9000)
-    Http4kBenchmarkServer(PostgresDatabase("tfb-database")).start(config)
+    Http4kBenchmarkServer(PostgresDatabase()).start(TfbApacheServer(9000))
 }
 
-private class TfbApacheServer(val port: Int) : ServerConfig {
+/**
+ * we need a custom config here because of how virtual hosting is required in the TFB
+ * environment. Normally we would just call the inbuilt ApacheServer(9000) function
+ */
+class TfbApacheServer(val port: Int) : ServerConfig {
     override fun toServer(http: HttpHandler): Http4kServer = object : Http4kServer {
         val handler = Http4kRequestHandler(http)
 

+ 3 - 3
frameworks/Kotlin/http4k/apache4/build.gradle

@@ -1,6 +1,6 @@
 dependencies {
-    api project(":core")
-    api "org.http4k:http4k-server-apache4:$http4k_version"
+    api(project(":core-jdbc"))
+    api("org.http4k:http4k-server-apache4:$http4k_version")
 }
 
 apply plugin: 'application'
@@ -8,7 +8,7 @@ mainClassName = "Http4kApache4ServerKt"
 apply plugin: 'com.github.johnrengelman.shadow'
 
 shadowJar {
-    baseName = "http4k-$project.name-benchmark"
+    baseName = "http4k-benchmark"
     classifier = null
     version = null
     mergeServiceFiles()

+ 1 - 1
frameworks/Kotlin/http4k/apache4/src/main/kotlin/Http4kApache4Server.kt

@@ -1,5 +1,5 @@
 import org.http4k.server.Apache4Server
 
 fun main() {
-    Http4kBenchmarkServer(PostgresDatabase("tfb-database")).start(Apache4Server(9000))
+    Http4kBenchmarkServer(PostgresDatabase()).start(Apache4Server(9000))
 }

+ 66 - 0
frameworks/Kotlin/http4k/benchmark_config.json

@@ -69,6 +69,28 @@
         "notes": "https://http4k.org",
         "versus": "servlet"
       },
+      "graalvm": {
+        "orm": "Raw",
+        "database_os": "Linux",
+        "cached_query_url": "/cached?queries=",
+        "db_url": "/db",
+        "fortune_url": "/fortunes",
+        "query_url": "/queries?queries=",
+        "update_url": "/updates?queries=",
+        "database": "Postgres",
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "port": 9000,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "framework": "http4k",
+        "language": "Kotlin",
+        "platform": "graalvm",
+        "webserver": "None",
+        "os": "Linux",
+        "notes": "https://http4k.org",
+        "versus": "servlet"
+      },
       "jetty": {
         "orm": "Raw",
         "database_os": "Linux",
@@ -91,6 +113,50 @@
         "notes": "https://http4k.org",
         "versus": "jetty"
       },
+      "jettyloom-jdbc": {
+        "orm": "Raw",
+        "database_os": "Linux",
+        "cached_query_url": "/cached?queries=",
+        "db_url": "/db",
+        "fortune_url": "/fortunes",
+        "query_url": "/queries?queries=",
+        "update_url": "/updates?queries=",
+        "database": "Postgres",
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "port": 9000,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "framework": "http4k",
+        "language": "Kotlin",
+        "platform": "jetty-loom-jdbc",
+        "webserver": "None",
+        "os": "Linux",
+        "notes": "https://http4k.org",
+        "versus": "jetty"
+      },
+      "jettyloom-pgclient": {
+        "orm": "Raw",
+        "database_os": "Linux",
+        "cached_query_url": "/cached?queries=",
+        "db_url": "/db",
+        "fortune_url": "/fortunes",
+        "query_url": "/queries?queries=",
+        "update_url": "/updates?queries=",
+        "database": "Postgres",
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "port": 9000,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "framework": "http4k",
+        "language": "Kotlin",
+        "platform": "jetty-loom-pgclient",
+        "webserver": "None",
+        "os": "Linux",
+        "notes": "https://http4k.org",
+        "versus": "jetty"
+      },
       "ktorcio": {
         "orm": "Raw",
         "database_os": "Linux",

+ 3 - 3
frameworks/Kotlin/http4k/build.gradle

@@ -1,6 +1,6 @@
 buildscript {
-    ext.kotlin_version = "1.6.21"
-    ext.http4k_version = "4.25.16.2"
+    ext.kotlin_version = "1.7.20"
+    ext.http4k_version = "4.33.3.0"
 
     repositories {
         mavenCentral()
@@ -30,7 +30,7 @@ allprojects {
     version = project.hasProperty('releaseVersion') ? project.releaseVersion : 'LOCAL'
     group = 'org.http4k'
 
-    compileTestKotlin.kotlinOptions.languageVersion = "1.6"
+    compileTestKotlin.kotlinOptions.languageVersion = "1.7"
 }
 
 dependencies {

+ 54 - 0
frameworks/Kotlin/http4k/config.toml

@@ -109,6 +109,42 @@ platform = "jetty"
 webserver = "None"
 versus = "jetty"
 
+[jettyloom-jdbc]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.update = "/updates?queries="
+urls.fortune = "/fortunes"
+urls.cached_query = "/cached?queries="
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "jetty-loom-jdbc"
+webserver = "None"
+versus = "jetty"
+
+[jettyloom-pgclient]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.update = "/updates?queries="
+urls.fortune = "/fortunes"
+urls.cached_query = "/cached?queries="
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "jetty-loom-pgclient"
+webserver = "None"
+versus = "jetty"
+
 [apache]
 urls.plaintext = "/plaintext"
 urls.json = "/json"
@@ -127,6 +163,24 @@ platform = "apache-httpcore"
 webserver = "None"
 versus = "servlet"
 
+[graalvm]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.update = "/updates?queries="
+urls.fortune = "/fortunes"
+urls.cached_query = "/cached?queries="
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "graalvm"
+webserver = "None"
+versus = "servlet"
+
 [ktorcio]
 urls.plaintext = "/plaintext"
 urls.json = "/json"

+ 5 - 0
frameworks/Kotlin/http4k/core-jdbc/build.gradle

@@ -0,0 +1,5 @@
+dependencies {
+    api(project(":core"))
+    api("com.zaxxer:HikariCP:5.0.1")
+    api("org.postgresql:postgresql:42.5.0")
+}

+ 94 - 0
frameworks/Kotlin/http4k/core-jdbc/src/main/kotlin/PostgresDatabase.kt

@@ -0,0 +1,94 @@
+import com.zaxxer.hikari.HikariConfig
+import com.zaxxer.hikari.HikariDataSource
+import org.http4k.format.Argo.number
+import org.http4k.format.Argo.obj
+import java.sql.Connection
+import java.sql.PreparedStatement
+import java.sql.ResultSet
+import javax.sql.DataSource
+
+class PostgresDatabase private constructor(private val dataSource: DataSource) : Database {
+
+    override fun findWorld() = withConnection { findWorld(randomWorld()) }
+
+    override fun loadAll() = withConnection { findAll() }
+
+    override fun findWorlds(count: Int) = withConnection {
+        (1..count).map { findWorld(randomWorld()) }
+    }
+
+    override fun updateWorlds(count: Int) = withConnection {
+        (1..count).map {
+            val id = randomWorld()
+            updateWorld(id)
+            findWorld(id)
+        }
+    }
+
+    private fun Connection.updateWorld(id: Int) = withStatement("UPDATE world SET randomNumber = ? WHERE id = ?") {
+        setInt(1, randomWorld())
+        setInt(2, id)
+        executeUpdate()
+    }
+
+    override fun fortunes() = withConnection {
+        val original =
+            withStatement("select * from fortune") { executeQuery().toResultsList { Fortune(getInt(1), getString(2)) } }
+        (original + Fortune(0, "Additional fortune added at request time.")).sortedBy { it.message }
+    }
+
+    companion object {
+        operator fun invoke(): Database =
+            PostgresDatabase(HikariConfig().run {
+                username = "benchmarkdbuser"
+                password = "benchmarkdbpass"
+                jdbcUrl = "jdbc:postgresql://tfb-database:5432/hello_world?" +
+                    "useSSL=false&" +
+                    "jdbcCompliantTruncation=false&" +
+                    "elideSetAutoCommits=true&" +
+                    "useLocalSessionState=true&" +
+                    "cachePrepStmts=true&" +
+                    "cacheCallableStmts=true&" +
+                    "alwaysSendSetIsolation=false&" +
+                    "prepStmtCacheSize=4096&" +
+                    "cacheServerConfiguration=true&" +
+                    "prepStmtCacheSqlLimit=2048&" +
+                    "traceProtocol=false&" +
+                    "useUnbufferedInput=false&" +
+                    "useReadAheadInput=false&" +
+                    "maintainTimeStats=false&" +
+                    "useServerPrepStmts=true&" +
+                    "cacheRSMetadata=true"
+                maximumPoolSize = 100
+                HikariDataSource(this)
+            })
+    }
+
+    private inline fun <T> withConnection(fn: Connection.() -> T): T = dataSource.connection.use(fn)
+
+    private inline fun <T> Connection.withStatement(stmt: String, fn: PreparedStatement.() -> T): T =
+        prepareStatement(stmt).use(fn)
+
+    private fun Connection.findWorld(id: Int) =
+        withStatement("SELECT id, randomNumber FROM world WHERE id = ?") {
+            setInt(1, id)
+            executeQuery().toResultsList {
+                obj("id" to number(getInt("id")), "randomNumber" to number(getInt("randomNumber")))
+            }.first()
+        }
+
+    private fun Connection.findAll() =
+        withStatement("SELECT id, randomNumber FROM world") {
+            executeQuery().toResultsList {
+                val id = getInt("id")
+                id to obj("id" to number(id), "randomNumber" to number(getInt("randomNumber")))
+            }.toMap()
+        }
+
+    private inline fun <T> ResultSet.toResultsList(fn: ResultSet.() -> T): List<T> =
+        mutableListOf<T>().apply {
+            while (next()) {
+                add(fn(this@toResultsList))
+            }
+        }
+}

+ 4 - 0
frameworks/Kotlin/http4k/core-pgclient/build.gradle

@@ -0,0 +1,4 @@
+dependencies {
+    api(project(":core"))
+    api('io.vertx:vertx-pg-client:4.3.4')
+}

+ 76 - 0
frameworks/Kotlin/http4k/core-pgclient/src/main/kotlin/PostgresDatabase.kt

@@ -0,0 +1,76 @@
+import io.vertx.core.Vertx
+import io.vertx.core.VertxOptions
+import io.vertx.pgclient.PgConnectOptions
+import io.vertx.pgclient.PgPool.client
+import io.vertx.sqlclient.PoolOptions
+import io.vertx.sqlclient.SqlClient
+import io.vertx.sqlclient.Tuple
+import org.http4k.format.Argo.number
+import org.http4k.format.Argo.obj
+
+class PostgresDatabase : Database {
+    private val queryPool: SqlClient
+    private val updatePool: SqlClient
+
+    init {
+        val vertx = Vertx.vertx(VertxOptions().setPreferNativeTransport(true))
+        val connectOptions = PgConnectOptions().apply {
+            port = 5432
+            cachePreparedStatements = true
+            host = "tfb-database"
+            database = "hello_world"
+            user = "benchmarkdbuser"
+            password = "benchmarkdbpass"
+        }
+        val clientOptions = PoolOptions().setMaxSize(64)
+        queryPool = client(vertx, connectOptions, clientOptions)
+        updatePool = client(vertx, connectOptions, clientOptions)
+    }
+
+    override fun findWorld() =
+        findWorld(randomWorld(), queryPool).map { it.toJson() }.toCompletionStage().toCompletableFuture().get()
+
+    override fun loadAll() = queryPool.preparedQuery("SELECT id, randomnumber FROM world ")
+        .execute()
+        .map {
+            it.associate {
+                it.getInteger("id") to (it.getInteger("id") to it.getInteger("randomnumber")).toJson()
+            }
+        }
+        .toCompletionStage().toCompletableFuture().get()
+
+    override fun findWorlds(count: Int) =
+        (1..count).map {
+            findWorld(randomWorld(), queryPool)
+                .map { it.toJson() }.toCompletionStage().toCompletableFuture().get()
+        }
+
+    override fun updateWorlds(count: Int) =
+        (1..count)
+            .map { randomWorld() to randomWorld() }
+            .map { update ->
+                updatePool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2")
+                    .execute(Tuple.of(update.first, update.second))
+                    .flatMap { findWorld(update.first, queryPool).map { it.toJson() } }
+                    .toCompletionStage().toCompletableFuture().get()
+            }
+
+    override fun fortunes() = queryPool.preparedQuery("SELECT id, message FROM fortune")
+        .execute()
+        .map { it.map { Fortune(it.getInteger(0), it.getString(1)) } }
+        .map { (it + Fortune(0, "Additional fortune added at request time.")) }
+        .toCompletionStage().toCompletableFuture().get()
+        .sortedBy { it.message }
+
+    companion object {
+        private fun findWorld(id: Int, pool: SqlClient) =
+            pool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1")
+                .execute(Tuple.of(id))
+                .map { rows ->
+                    val r = rows.iterator().next()
+                    r.getInteger("id") to r.getInteger("randomnumber")
+                }
+    }
+}
+
+private fun Pair<Int, Int>.toJson() = obj("id" to number(first), "randomNumber" to number(second))

+ 7 - 10
frameworks/Kotlin/http4k/core/build.gradle

@@ -1,12 +1,9 @@
 dependencies {
-    api "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
-    api "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
-    api "org.http4k:http4k-core:$http4k_version"
-    api "org.http4k:http4k-format-jackson:$http4k_version"
-    api "org.http4k:http4k-template-pebble:$http4k_version"
-    api "org.apache.commons:commons-lang3:3.11"
-    api "com.zaxxer:HikariCP:3.4.5"
-    api "org.postgresql:postgresql:42.2.16"
-    api "org.cache2k:cache2k-base-bom:1.2.4.Final"
-
+    api("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
+    api("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")
+    api("org.http4k:http4k-core:$http4k_version")
+    api("org.http4k:http4k-format-argo:$http4k_version")
+    api("org.http4k:http4k-template-pebble:$http4k_version")
+    api("org.apache.commons:commons-lang3:3.12.0")
+    api("org.cache2k:cache2k-core:2.6.1.Final")
 }

+ 21 - 0
frameworks/Kotlin/http4k/core/src/main/kotlin/AddHeaders.kt

@@ -0,0 +1,21 @@
+import org.apache.commons.lang3.time.FastDateFormat
+import org.http4k.core.Filter
+import java.util.TimeZone
+
+fun AddHeaders(addDate: Boolean): Filter {
+    val dateFormat = FastDateFormat.getInstance("EEE, d MMM yyyy HH:mm:ss 'GMT'", TimeZone.getTimeZone("GMT"))
+    val filter = Filter { next ->
+        {
+            next(it).let {
+                it.headers(
+                    listOf(
+                        "Server" to "http4k",
+                        "Content-Length" to it.body.length.toString(),
+                        "Date" to if (addDate) dateFormat.format(System.currentTimeMillis()) else null
+                    )
+                )
+            }
+        }
+    }
+    return filter
+}

+ 6 - 100
frameworks/Kotlin/http4k/core/src/main/kotlin/Database.kt

@@ -1,15 +1,7 @@
-import com.fasterxml.jackson.databind.JsonNode
-import com.zaxxer.hikari.HikariConfig
-import com.zaxxer.hikari.HikariDataSource
+import argo.jdom.JsonNode
+import org.cache2k.Cache
 import org.cache2k.Cache2kBuilder
-import org.cache2k.IntCache
-import org.http4k.format.Jackson.number
-import org.http4k.format.Jackson.obj
-import java.sql.Connection
-import java.sql.PreparedStatement
-import java.sql.ResultSet
 import java.util.Random
-import javax.sql.DataSource
 
 interface Database {
     fun findWorld(): JsonNode
@@ -26,107 +18,21 @@ class CachedDatabase(private val delegate: Database) : Database by delegate {
         .name("cachedWorld")
         .eternal(true)
         .entryCapacity(TOTAL_DB_ROWS.toLong())
-        .buildForIntKey()
+        .build()
         .apply {
             refresh()
         }
 
-    private fun IntCache<JsonNode>.refresh() {
+    private fun Cache<Int, JsonNode>.refresh() {
         putAll(delegate.loadAll())
     }
 
     override fun findWorlds(count: Int) = (1..count).map { cache.peek(randomWorld()) }
 
     override fun updateWorlds(count: Int) =
-        delegate.updateWorlds(count).apply {
-            cache.refresh() // massively inefficient, but :shrug:
-        }
+        delegate.updateWorlds(count).onEach { cache.put(it.getNumberValue("id").toInt(), it) }
 
     override fun loadAll(): Map<Int, JsonNode> = cache.asMap()
 }
 
-class PostgresDatabase private constructor(private val dataSource: DataSource) : Database {
-
-    override fun findWorld() = withConnection { findWorld(randomWorld()) }
-
-    override fun loadAll(): Map<Int, JsonNode> = withConnection { findAll() }
-
-    override fun findWorlds(count: Int) = withConnection {
-        (1..count).map { findWorld(randomWorld()) }
-    }
-
-    override fun updateWorlds(count: Int) = withConnection {
-        (1..count).map {
-            val id = randomWorld()
-            updateWorld(id)
-            findWorld(id)
-        }
-    }
-
-    private fun Connection.updateWorld(id: Int) = withStatement("UPDATE world SET randomNumber = ? WHERE id = ?") {
-        setInt(1, randomWorld())
-        setInt(2, id)
-        executeUpdate()
-    }
-
-    override fun fortunes() = withConnection {
-        val original = withStatement("select * from fortune") { executeQuery().toResultsList { Fortune(getInt(1), getString(2)) } }
-        (original + Fortune(0, "Additional fortune added at request time.")).sortedBy { it.message }
-    }
-
-    companion object {
-        operator fun invoke(host: String): Database =
-            PostgresDatabase(HikariConfig().run {
-                username = "benchmarkdbuser"
-                password = "benchmarkdbpass"
-                jdbcUrl = "jdbc:postgresql://$host:5432/hello_world?" +
-                    "useSSL=false&" +
-                    "jdbcCompliantTruncation=false&" +
-                    "elideSetAutoCommits=true&" +
-                    "useLocalSessionState=true&" +
-                    "cachePrepStmts=true&" +
-                    "cacheCallableStmts=true&" +
-                    "alwaysSendSetIsolation=false&" +
-                    "prepStmtCacheSize=4096&" +
-                    "cacheServerConfiguration=true&" +
-                    "prepStmtCacheSqlLimit=2048&" +
-                    "traceProtocol=false&" +
-                    "useUnbufferedInput=false&" +
-                    "useReadAheadInput=false&" +
-                    "maintainTimeStats=false&" +
-                    "useServerPrepStmts=true&" +
-                    "cacheRSMetadata=true"
-                maximumPoolSize = 100
-                HikariDataSource(this)
-            })
-    }
-
-    private inline fun <T> withConnection(fn: Connection.() -> T): T = dataSource.connection.use(fn)
-
-    private inline fun <T> Connection.withStatement(stmt: String, fn: PreparedStatement.() -> T): T = prepareStatement(stmt).use(fn)
-
-    private fun Connection.findWorld(id: Int) =
-        withStatement("SELECT * FROM world WHERE id = ?") {
-            setInt(1, id)
-            executeQuery().toResultsList {
-                obj("id" to number(getInt("id")), "randomNumber" to number(getInt("randomNumber")))
-            }.first()
-        }
-
-    private fun Connection.findAll() =
-        withStatement("SELECT * FROM world") {
-            executeQuery().toResultsList {
-                val id = getInt("id")
-                id to obj("id" to number(id), "randomNumber" to number(getInt("randomNumber")))
-            }.toMap()
-        }
-
-    private inline fun <T> ResultSet.toResultsList(fn: ResultSet.() -> T): List<T> =
-        mutableListOf<T>().apply {
-            while (next()) {
-                add(fn(this@toResultsList))
-            }
-        }
-}
-
-private fun randomWorld() = Random().nextInt(TOTAL_DB_ROWS - 1) + 1
+fun randomWorld() = Random().nextInt(TOTAL_DB_ROWS - 1) + 1

+ 1 - 1
frameworks/Kotlin/http4k/core/src/main/kotlin/FortunesRoute.kt

@@ -19,4 +19,4 @@ object FortunesRoute {
     operator fun invoke(db: Database) = "/fortunes" bind GET to {
         Response(OK).with(viewBody of FortunesList(db.fortunes()))
     }
-}
+}

+ 3 - 21
frameworks/Kotlin/http4k/core/src/main/kotlin/Http4kBenchmarkServer.kt

@@ -1,29 +1,12 @@
-import org.apache.commons.lang3.time.FastDateFormat.getInstance
-import org.http4k.core.Filter
 import org.http4k.core.HttpHandler
 import org.http4k.core.then
 import org.http4k.routing.routes
 import org.http4k.server.ServerConfig
 import org.http4k.server.asServer
-import java.util.TimeZone.getTimeZone
 
-object Http4kBenchmarkServer {
-    private val dateFormat = getInstance("EEE, d MMM yyyy HH:mm:ss 'GMT'", getTimeZone("GMT"))
-
-    private fun headers(addDate: Boolean) = Filter { next ->
-        {
-            next(it).let {
-                it.headers(listOf(
-                    "Server" to "http4k",
-                    "Content-Length" to it.body.length.toString(),
-                    "Date" to if (addDate) dateFormat.format(System.currentTimeMillis()) else null
-                ))
-            }
-        }
-    }
-
-    operator fun invoke(database: Database, addDateHeader: Boolean = true) =
-        headers(addDateHeader).then(
+fun Http4kBenchmarkServer(database: Database, addDateHeader: Boolean = true) =
+    AddHeaders(addDateHeader)
+        .then(
             routes(
                 JsonRoute(),
                 PlainTextRoute(),
@@ -34,6 +17,5 @@ object Http4kBenchmarkServer {
                 WorldRoutes.cachedRoute(database)
             )
         )
-}
 
 fun HttpHandler.start(config: ServerConfig) = asServer(config).start().block()

+ 3 - 3
frameworks/Kotlin/http4k/core/src/main/kotlin/JsonRoute.kt

@@ -3,9 +3,9 @@ import org.http4k.core.Method.GET
 import org.http4k.core.Response
 import org.http4k.core.Status.Companion.OK
 import org.http4k.core.with
-import org.http4k.format.Jackson.json
-import org.http4k.format.Jackson.obj
-import org.http4k.format.Jackson.string
+import org.http4k.format.Argo.json
+import org.http4k.format.Argo.obj
+import org.http4k.format.Argo.string
 import org.http4k.routing.bind
 
 object JsonRoute {

+ 2 - 2
frameworks/Kotlin/http4k/core/src/main/kotlin/WorldRoutes.kt

@@ -3,8 +3,8 @@ import org.http4k.core.Method.GET
 import org.http4k.core.Response
 import org.http4k.core.Status.Companion.OK
 import org.http4k.core.with
-import org.http4k.format.Jackson.array
-import org.http4k.format.Jackson.json
+import org.http4k.format.Argo.array
+import org.http4k.format.Argo.json
 import org.http4k.lens.Query
 import org.http4k.routing.RoutingHttpHandler
 import org.http4k.routing.bind

+ 21 - 0
frameworks/Kotlin/http4k/graalvm/build.gradle

@@ -0,0 +1,21 @@
+dependencies {
+    api(project(":core-jdbc"))
+    api(project(":apache"))
+}
+
+apply plugin: 'application'
+mainClassName = "http4k.Http4kGraalVMBenchmarkServerKt"
+apply plugin: 'com.github.johnrengelman.shadow'
+
+jar {
+    manifest {
+        attributes 'Main-Class': mainClassName
+    }
+}
+
+shadowJar {
+    baseName = "http4k-benchmark"
+    classifier = null
+    version = null
+    mergeServiceFiles()
+}

+ 92 - 0
frameworks/Kotlin/http4k/graalvm/config/reflect-config.json

@@ -0,0 +1,92 @@
+[
+  {
+    "name": "com.zaxxer.hikari.HikariConfig",
+    "allDeclaredFields": true
+  },
+  {
+    "name": "com.zaxxer.hikari.HikariDataSource",
+    "methods": [
+      {
+        "name": "<init>",
+        "parameterTypes": []
+      }
+    ],
+    "allDeclaredFields": true
+  },
+  {
+    "name": "com.zaxxer.hikari.util.ConcurrentBag$IConcurrentBagEntry[]"
+  },
+  {
+    "name": "Fortune",
+    "allDeclaredConstructors": true,
+    "allPublicConstructors": true,
+    "allDeclaredMethods": true,
+    "allPublicMethods": true,
+    "allDeclaredClasses": true,
+    "allPublicClasses": true
+  },
+  {
+    "name": "FortunesList",
+    "allDeclaredConstructors": true,
+    "allPublicConstructors": true,
+    "allDeclaredMethods": true,
+    "allPublicMethods": true,
+    "allDeclaredClasses": true,
+    "allPublicClasses": true
+  },
+  {
+    "name": "com.zaxxer.hikari.util.ConcurrentBag",
+    "allDeclaredConstructors": true,
+    "allPublicConstructors": true,
+    "allDeclaredMethods": true,
+    "allPublicMethods": true,
+    "allDeclaredClasses": true,
+    "allPublicClasses": true
+  },
+  {
+    "name": "com.zaxxer.hikari.pool.PoolEntry",
+    "allDeclaredConstructors": true,
+    "allPublicConstructors": true,
+    "allDeclaredMethods": true,
+    "allPublicMethods": true,
+    "allDeclaredClasses": true,
+    "allPublicClasses": true
+  },
+  {
+    "name": "java.sql.Statement[]"
+  },
+  {
+    "name": "org.postgresql.Driver"
+  },
+  {
+    "name": "java.lang.SecurityManager",
+    "methods": [
+      {
+        "name": "checkPermission",
+        "parameterTypes": [
+          "java.security.Permission"
+        ]
+      }
+    ]
+  },
+  {
+    "name": "java.lang.System",
+    "methods": [
+      {
+        "name": "getSecurityManager",
+        "parameterTypes": []
+      }
+    ]
+  },
+  {
+    "name": "java.security.AccessController",
+    "methods": [
+      {
+        "name": "doPrivileged",
+        "parameterTypes": [
+          "java.security.PrivilegedExceptionAction"
+        ]
+      }
+    ]
+  }
+]

+ 9 - 0
frameworks/Kotlin/http4k/graalvm/config/resource-config.json

@@ -0,0 +1,9 @@
+{
+  "resources": {
+    "includes": [
+      {
+        "pattern": ".*peb$"
+      }
+    ]
+  }
+}

+ 10 - 0
frameworks/Kotlin/http4k/graalvm/src/main/kotlin/http4k/Http4kGraalVMBenchmarkServer.kt

@@ -0,0 +1,10 @@
+package http4k
+
+import Http4kBenchmarkServer
+import PostgresDatabase
+import TfbApacheServer
+import start
+
+fun main() {
+    Http4kBenchmarkServer(PostgresDatabase()).start(TfbApacheServer(9000))
+}

+ 4 - 2
frameworks/Kotlin/http4k/http4k-apache.dockerfile

@@ -1,12 +1,14 @@
-FROM gradle:7.4.2-jdk11
+FROM gradle:7.5.1-jdk11
 USER root
 WORKDIR /http4k
 COPY build.gradle build.gradle
 COPY settings.gradle settings.gradle
 COPY apache apache
 COPY core core
+COPY core-jdbc core-jdbc
+COPY core-pgclient core-pgclient
 RUN gradle --quiet apache:shadowJar
 
 EXPOSE 9000
 
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "apache/build/libs/http4k-apache-benchmark.jar"]
+CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "apache/build/libs/http4k-benchmark.jar"]

+ 4 - 2
frameworks/Kotlin/http4k/http4k-apache4.dockerfile

@@ -1,12 +1,14 @@
-FROM gradle:7.4.2-jdk11
+FROM gradle:7.5.1-jdk11
 USER root
 WORKDIR /http4k
 COPY build.gradle build.gradle
 COPY settings.gradle settings.gradle
 COPY apache4 apache4
 COPY core core
+COPY core-jdbc core-jdbc
+COPY core-pgclient core-pgclient
 RUN gradle --quiet apache4:shadowJar
 
 EXPOSE 9000
 
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "apache4/build/libs/http4k-apache4-benchmark.jar"]
+CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "apache4/build/libs/http4k-benchmark.jar"]

+ 33 - 0
frameworks/Kotlin/http4k/http4k-graalvm.dockerfile

@@ -0,0 +1,33 @@
+FROM gradle:7.5.1-jdk11 as gradle
+USER root
+WORKDIR /http4k
+COPY build.gradle build.gradle
+COPY settings.gradle settings.gradle
+COPY apache apache
+COPY core core
+COPY core-jdbc core-jdbc
+COPY core-pgclient core-pgclient
+COPY graalvm graalvm
+
+RUN gradle --quiet graalvm:shadowJar
+
+FROM ghcr.io/graalvm/graalvm-ce:ol7-java17-22.3.0 as graalvm
+RUN gu install native-image
+
+COPY --from=gradle /http4k/core/src/main/resources/* /home/app/http4k-graalvm/
+COPY --from=gradle /http4k/graalvm/build/libs/http4k-benchmark.jar /home/app/http4k-graalvm/
+COPY --from=gradle /http4k/graalvm/config/*.json /home/app/http4k-graalvm/
+
+WORKDIR /home/app/http4k-graalvm
+
+RUN native-image \
+    -H:ReflectionConfigurationFiles=reflect-config.json \
+    -H:ResourceConfigurationFiles=resource-config.json \
+    --initialize-at-build-time="org.slf4j.LoggerFactory,org.slf4j.simple.SimpleLogger,org.slf4j.impl.StaticLoggerBinder" \
+    --no-fallback -cp http4k-benchmark.jar http4k.Http4kGraalVMBenchmarkServerKt
+
+FROM frolvlad/alpine-glibc
+RUN apk update && apk add libstdc++
+EXPOSE 9000
+COPY --from=graalvm /home/app/http4k-graalvm/http4k.http4kgraalvmbenchmarkserverkt /app/http4k-graalvm
+ENTRYPOINT ["/app/http4k-graalvm"]

+ 4 - 2
frameworks/Kotlin/http4k/http4k-jetty.dockerfile

@@ -1,12 +1,14 @@
-FROM gradle:7.4.2-jdk11
+FROM gradle:7.5.1-jdk11
 USER root
 WORKDIR /http4k
 COPY build.gradle build.gradle
 COPY settings.gradle settings.gradle
 COPY core core
+COPY core-jdbc core-jdbc
+COPY core-pgclient core-pgclient
 COPY jetty jetty
 RUN gradle --quiet jetty:shadowJar
 
 EXPOSE 9000
 
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "jetty/build/libs/http4k-jetty-benchmark.jar"]
+CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "jetty/build/libs/http4k-benchmark.jar"]

+ 49 - 0
frameworks/Kotlin/http4k/http4k-jettyloom-jdbc.dockerfile

@@ -0,0 +1,49 @@
+# START: WE ARE BUILDING A CUSTOM GRADLE IMAGE BECAUSE JAVA 19 IS NOT CURRENTLY SUPPORTED IN PUBLIC IMAGES
+FROM eclipse-temurin:19-jdk-alpine as gradle
+
+CMD ["gradle"]
+
+ENV GRADLE_HOME /opt/gradle
+
+RUN set -o errexit -o nounset \
+    && echo "Adding gradle user and group" \
+    && addgroup --system --gid 1000 gradle \
+    && adduser --system --ingroup gradle --uid 1000 --shell /bin/ash gradle \
+    && mkdir /home/gradle/.gradle \
+    && chown -R gradle:gradle /home/gradle \
+    \
+    && echo "Symlinking root Gradle cache to gradle Gradle cache" \
+    && ln -s /home/gradle/.gradle /root/.gradle
+
+VOLUME /home/gradle/.gradle
+
+WORKDIR /home/gradle
+
+ENV GRADLE_VERSION 7.6-milestone-1
+ARG GRADLE_DOWNLOAD_SHA256=f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4
+RUN set -o errexit -o nounset \
+    && wget --no-verbose --output-document=gradle.zip "https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip" \
+    && unzip -qq gradle.zip \
+    && rm gradle.zip \
+    && mv "gradle-${GRADLE_VERSION}" "${GRADLE_HOME}/" \
+    && ln -s "${GRADLE_HOME}/bin/gradle" /usr/bin/gradle \
+    && gradle --version
+# END : WE ARE BUILDING A CUSTOM GRADLE IMAGE BECAUSE JAVA 19 IS NOT CURRENTLY SUPPORTED IN PUBLIC IMAGES
+
+USER root
+WORKDIR /http4k
+COPY build.gradle build.gradle
+COPY settings.gradle settings.gradle
+COPY core core
+COPY core-jdbc core-jdbc
+COPY jettyloom-jdbc jettyloom-jdbc
+RUN gradle --quiet jettyloom-jdbc:shadowJar
+
+FROM openjdk:19-jdk-slim as java
+COPY --from=gradle /http4k/jettyloom-jdbc/build/libs/http4k-benchmark.jar /home/app/
+
+WORKDIR /home/app
+
+EXPOSE 9000
+
+CMD ["java", "-server", "-XX:+UseNUMA", "--enable-preview", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "/home/app/http4k-benchmark.jar"]

+ 49 - 0
frameworks/Kotlin/http4k/http4k-jettyloom-pgclient.dockerfile

@@ -0,0 +1,49 @@
+# START: WE ARE BUILDING A CUSTOM GRADLE IMAGE BECAUSE JAVA 19 IS NOT CURRENTLY SUPPORTED IN PUBLIC IMAGES
+FROM eclipse-temurin:19-jdk-alpine as gradle
+
+CMD ["gradle"]
+
+ENV GRADLE_HOME /opt/gradle
+
+RUN set -o errexit -o nounset \
+    && echo "Adding gradle user and group" \
+    && addgroup --system --gid 1000 gradle \
+    && adduser --system --ingroup gradle --uid 1000 --shell /bin/ash gradle \
+    && mkdir /home/gradle/.gradle \
+    && chown -R gradle:gradle /home/gradle \
+    \
+    && echo "Symlinking root Gradle cache to gradle Gradle cache" \
+    && ln -s /home/gradle/.gradle /root/.gradle
+
+VOLUME /home/gradle/.gradle
+
+WORKDIR /home/gradle
+
+ENV GRADLE_VERSION 7.6-milestone-1
+ARG GRADLE_DOWNLOAD_SHA256=f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4
+RUN set -o errexit -o nounset \
+    && wget --no-verbose --output-document=gradle.zip "https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip" \
+    && unzip -qq gradle.zip \
+    && rm gradle.zip \
+    && mv "gradle-${GRADLE_VERSION}" "${GRADLE_HOME}/" \
+    && ln -s "${GRADLE_HOME}/bin/gradle" /usr/bin/gradle \
+    && gradle --version
+# END : WE ARE BUILDING A CUSTOM GRADLE IMAGE BECAUSE JAVA 19 IS NOT CURRENTLY SUPPORTED IN PUBLIC IMAGES
+
+USER root
+WORKDIR /http4k
+COPY build.gradle build.gradle
+COPY settings.gradle settings.gradle
+COPY core core
+COPY core-pgclient core-pgclient
+COPY jettyloom-pgclient jettyloom-pgclient
+RUN gradle --quiet jettyloom-pgclient:shadowJar
+
+FROM openjdk:19-jdk-slim as java
+COPY --from=gradle /http4k/jettyloom-pgclient/build/libs/http4k-benchmark.jar /home/app/
+
+WORKDIR /home/app
+
+EXPOSE 9000
+
+CMD ["java", "-server", "-XX:+UseNUMA", "--enable-preview", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "/home/app/http4k-benchmark.jar"]

+ 4 - 2
frameworks/Kotlin/http4k/http4k-ktorcio.dockerfile

@@ -1,12 +1,14 @@
-FROM gradle:7.4.2-jdk11
+FROM gradle:7.5.1-jdk11
 USER root
 WORKDIR /http4k
 COPY build.gradle build.gradle
 COPY settings.gradle settings.gradle
 COPY core core
+COPY core-jdbc core-jdbc
+COPY core-pgclient core-pgclient
 COPY ktorcio ktorcio
 RUN gradle --quiet ktorcio:shadowJar
 
 EXPOSE 9000
 
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "ktorcio/build/libs/http4k-ktorcio-benchmark.jar"]
+CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "ktorcio/build/libs/http4k-benchmark.jar"]

+ 4 - 2
frameworks/Kotlin/http4k/http4k-ktornetty.dockerfile

@@ -1,12 +1,14 @@
-FROM gradle:7.4.2-jdk11
+FROM gradle:7.5.1-jdk11
 USER root
 WORKDIR /http4k
 COPY build.gradle build.gradle
 COPY settings.gradle settings.gradle
 COPY core core
+COPY core-jdbc core-jdbc
+COPY core-pgclient core-pgclient
 COPY ktornetty ktornetty
 RUN gradle --quiet ktornetty:shadowJar
 
 EXPOSE 9000
 
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "ktornetty/build/libs/http4k-ktornetty-benchmark.jar"]
+CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "ktornetty/build/libs/http4k-benchmark.jar"]

+ 4 - 2
frameworks/Kotlin/http4k/http4k-netty.dockerfile

@@ -1,12 +1,14 @@
-FROM gradle:7.4.2-jdk11
+FROM gradle:7.5.1-jdk11
 USER root
 WORKDIR /http4k
 COPY build.gradle build.gradle
 COPY settings.gradle settings.gradle
 COPY core core
+COPY core-jdbc core-jdbc
+COPY core-pgclient core-pgclient
 COPY netty netty
 RUN gradle --quiet netty:shadowJar
 
 EXPOSE 9000
 
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "netty/build/libs/http4k-netty-benchmark.jar"]
+CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "netty/build/libs/http4k-benchmark.jar"]

+ 4 - 2
frameworks/Kotlin/http4k/http4k-ratpack.dockerfile

@@ -1,12 +1,14 @@
-FROM gradle:7.4.2-jdk11
+FROM gradle:7.5.1-jdk11
 USER root
 WORKDIR /http4k
 COPY build.gradle build.gradle
 COPY settings.gradle settings.gradle
 COPY core core
+COPY core-jdbc core-jdbc
+COPY core-pgclient core-pgclient
 COPY ratpack ratpack
 RUN gradle --quiet ratpack:shadowJar
 
 EXPOSE 9000
 
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "ratpack/build/libs/http4k-ratpack-benchmark.jar"]
+CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "ratpack/build/libs/http4k-benchmark.jar"]

+ 4 - 2
frameworks/Kotlin/http4k/http4k-undertow.dockerfile

@@ -1,12 +1,14 @@
-FROM gradle:7.4.2-jdk11
+FROM gradle:7.5.1-jdk11
 USER root
 WORKDIR /http4k
 COPY build.gradle build.gradle
 COPY settings.gradle settings.gradle
 COPY core core
+COPY core-jdbc core-jdbc
+COPY core-pgclient core-pgclient
 COPY undertow undertow
 RUN gradle --quiet undertow:shadowJar
 
 EXPOSE 9000
 
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "undertow/build/libs/http4k-undertow-benchmark.jar"]
+CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "undertow/build/libs/http4k-benchmark.jar"]

+ 4 - 2
frameworks/Kotlin/http4k/http4k.dockerfile

@@ -1,12 +1,14 @@
-FROM gradle:7.4.2-jdk11
+FROM gradle:7.5.1-jdk11
 USER root
 WORKDIR /http4k
 COPY build.gradle build.gradle
 COPY settings.gradle settings.gradle
 COPY core core
+COPY core-jdbc core-jdbc
+COPY core-pgclient core-pgclient
 COPY sunhttp sunhttp
 RUN gradle --quiet sunhttp:shadowJar
 
 EXPOSE 9000
 
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "sunhttp/build/libs/http4k-sunhttp-benchmark.jar"]
+CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "sunhttp/build/libs/http4k-benchmark.jar"]

+ 3 - 3
frameworks/Kotlin/http4k/jetty/build.gradle

@@ -1,6 +1,6 @@
 dependencies {
-    api project(":core")
-    api "org.http4k:http4k-server-jetty:$http4k_version"
+    api(project(":core-jdbc"))
+    api("org.http4k:http4k-server-jetty:$http4k_version")
 }
 
 apply plugin: 'application'
@@ -8,7 +8,7 @@ mainClassName = "Http4kJettyServerKt"
 apply plugin: 'com.github.johnrengelman.shadow'
 
 shadowJar {
-    baseName = "http4k-$project.name-benchmark"
+    baseName = "http4k-benchmark"
     classifier = null
     version = null
     mergeServiceFiles()

+ 1 - 1
frameworks/Kotlin/http4k/jetty/src/main/kotlin/Http4kJettyServer.kt

@@ -1,5 +1,5 @@
 import org.http4k.server.Jetty
 
 fun main() {
-    Http4kBenchmarkServer(PostgresDatabase("tfb-database"), false).start(Jetty(9000))
+    Http4kBenchmarkServer(PostgresDatabase(), false).start(Jetty(9000))
 }

+ 14 - 0
frameworks/Kotlin/http4k/jettyloom-jdbc/build.gradle

@@ -0,0 +1,14 @@
+dependencies {
+    api(project(":core-jdbc"))
+    api("org.http4k:http4k-server-jetty:$http4k_version")
+}
+
+apply plugin: 'application'
+mainClassName = "Http4kJettyLoomServerKt"
+apply plugin: 'com.github.johnrengelman.shadow'
+
+shadowJar {
+    baseName = "http4k-benchmark"
+    classifier = null
+    version = null
+}

+ 3 - 0
frameworks/Kotlin/http4k/jettyloom-jdbc/src/main/kotlin/Http4kJettyLoomServer.kt

@@ -0,0 +1,3 @@
+fun main() {
+    Http4kBenchmarkServer(PostgresDatabase(), false).start(JettyLoom(9000))
+}

+ 47 - 0
frameworks/Kotlin/http4k/jettyloom-jdbc/src/main/kotlin/JettyLoom.kt

@@ -0,0 +1,47 @@
+import org.eclipse.jetty.server.*
+import org.eclipse.jetty.util.thread.ThreadPool
+import org.http4k.core.HttpHandler
+import org.http4k.server.Http4kServer
+import org.http4k.server.ServerConfig
+import org.http4k.server.ServerConfig.StopMode.Graceful
+import org.http4k.server.http
+import org.http4k.server.toJettyHandler
+import java.time.Duration.ofSeconds
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit.NANOSECONDS
+import kotlin.Long.Companion.MAX_VALUE
+
+class JettyLoom(private val port: Int) : ServerConfig {
+    private val server = Server(LoomThreadPool())
+
+    override val stopMode = Graceful(ofSeconds(5))
+
+    override fun toServer(http: HttpHandler) = server.run {
+        addConnector(http(port)(this))
+        insertHandler(http.toJettyHandler(true))
+        object : Http4kServer {
+            override fun start(): Http4kServer = apply { server.start() }
+            override fun stop(): Http4kServer = apply { server.stop() }
+            override fun port(): Int = if (port > 0) port else server.uri.port
+        }
+    }
+}
+
+class LoomThreadPool : ThreadPool {
+    private val executorService = Executors.newVirtualThreadPerTaskExecutor()
+
+    @Throws(InterruptedException::class)
+    override fun join() {
+        executorService.awaitTermination(MAX_VALUE, NANOSECONDS)
+    }
+
+    override fun getThreads() = 1
+
+    override fun getIdleThreads() = 1
+
+    override fun isLowOnThreads() = false
+
+    override fun execute(command: Runnable) {
+        executorService.submit(command)
+    }
+}

+ 14 - 0
frameworks/Kotlin/http4k/jettyloom-pgclient/build.gradle

@@ -0,0 +1,14 @@
+dependencies {
+    api(project(":core-pgclient"))
+    api("org.http4k:http4k-server-jetty:$http4k_version")
+}
+
+apply plugin: 'application'
+mainClassName = "Http4kJettyLoomServerKt"
+apply plugin: 'com.github.johnrengelman.shadow'
+
+shadowJar {
+    baseName = "http4k-benchmark"
+    classifier = null
+    version = null
+}

+ 3 - 0
frameworks/Kotlin/http4k/jettyloom-pgclient/src/main/kotlin/Http4kJettyLoomServer.kt

@@ -0,0 +1,3 @@
+fun main() {
+    Http4kBenchmarkServer(PostgresDatabase(), false).start(JettyLoom(9000))
+}

+ 47 - 0
frameworks/Kotlin/http4k/jettyloom-pgclient/src/main/kotlin/JettyLoom.kt

@@ -0,0 +1,47 @@
+import org.eclipse.jetty.server.*
+import org.eclipse.jetty.util.thread.ThreadPool
+import org.http4k.core.HttpHandler
+import org.http4k.server.Http4kServer
+import org.http4k.server.ServerConfig
+import org.http4k.server.ServerConfig.StopMode.Graceful
+import org.http4k.server.http
+import org.http4k.server.toJettyHandler
+import java.time.Duration.ofSeconds
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit.NANOSECONDS
+import kotlin.Long.Companion.MAX_VALUE
+
+class JettyLoom(private val port: Int) : ServerConfig {
+    private val server = Server(LoomThreadPool())
+
+    override val stopMode = Graceful(ofSeconds(5))
+
+    override fun toServer(http: HttpHandler) = server.run {
+        addConnector(http(port)(this))
+        insertHandler(http.toJettyHandler(true))
+        object : Http4kServer {
+            override fun start(): Http4kServer = apply { server.start() }
+            override fun stop(): Http4kServer = apply { server.stop() }
+            override fun port(): Int = if (port > 0) port else server.uri.port
+        }
+    }
+}
+
+class LoomThreadPool : ThreadPool {
+    private val executorService = Executors.newVirtualThreadPerTaskExecutor()
+
+    @Throws(InterruptedException::class)
+    override fun join() {
+        executorService.awaitTermination(MAX_VALUE, NANOSECONDS)
+    }
+
+    override fun getThreads() = 1
+
+    override fun getIdleThreads() = 1
+
+    override fun isLowOnThreads() = false
+
+    override fun execute(command: Runnable) {
+        executorService.submit(command)
+    }
+}

+ 3 - 3
frameworks/Kotlin/http4k/ktorcio/build.gradle

@@ -1,6 +1,6 @@
 dependencies {
-    api project(":core")
-    api "org.http4k:http4k-server-ktorcio:$http4k_version"
+    api(project(":core-jdbc"))
+    api("org.http4k:http4k-server-ktorcio:$http4k_version")
 }
 
 apply plugin: 'application'
@@ -8,7 +8,7 @@ mainClassName = "Http4kKtorCIOServerKt"
 apply plugin: 'com.github.johnrengelman.shadow'
 
 shadowJar {
-    baseName = "http4k-$project.name-benchmark"
+    baseName = "http4k-benchmark"
     classifier = null
     version = null
     mergeServiceFiles()

+ 1 - 1
frameworks/Kotlin/http4k/ktorcio/src/main/kotlin/Http4kKtorCIOServer.kt

@@ -1,5 +1,5 @@
 import org.http4k.server.KtorCIO
 
 fun main() {
-    Http4kBenchmarkServer(PostgresDatabase("tfb-database")).start(KtorCIO(9000))
+    Http4kBenchmarkServer(PostgresDatabase()).start(KtorCIO(9000))
 }

+ 3 - 3
frameworks/Kotlin/http4k/ktornetty/build.gradle

@@ -1,6 +1,6 @@
 dependencies {
-    api project(":core")
-    api "org.http4k:http4k-server-ktornetty:$http4k_version"
+    api(project(":core-jdbc"))
+    api("org.http4k:http4k-server-ktornetty:$http4k_version")
 }
 
 apply plugin: 'application'
@@ -8,7 +8,7 @@ mainClassName = "Http4kKtorNettyServerKt"
 apply plugin: 'com.github.johnrengelman.shadow'
 
 shadowJar {
-    baseName = "http4k-$project.name-benchmark"
+    baseName = "http4k-benchmark"
     classifier = null
     version = null
     mergeServiceFiles()

+ 1 - 1
frameworks/Kotlin/http4k/ktornetty/src/main/kotlin/Http4kKtorNettyServer.kt

@@ -1,5 +1,5 @@
 import org.http4k.server.KtorNetty
 
 fun main() {
-    Http4kBenchmarkServer(PostgresDatabase("tfb-database")).start(KtorNetty(9000))
+    Http4kBenchmarkServer(PostgresDatabase()).start(KtorNetty(9000))
 }

+ 3 - 3
frameworks/Kotlin/http4k/netty/build.gradle

@@ -1,6 +1,6 @@
 dependencies {
-    api project(":core")
-    api "org.http4k:http4k-server-netty:$http4k_version"
+    api(project(":core-jdbc"))
+    api("org.http4k:http4k-server-netty:$http4k_version")
 }
 
 apply plugin: 'application'
@@ -8,7 +8,7 @@ mainClassName = "Http4kNettyServerKt"
 apply plugin: 'com.github.johnrengelman.shadow'
 
 shadowJar {
-    baseName = "http4k-$project.name-benchmark"
+    baseName = "http4k-benchmark"
     classifier = null
     version = null
     mergeServiceFiles()

+ 1 - 1
frameworks/Kotlin/http4k/netty/src/main/kotlin/Http4kNettyServer.kt

@@ -1,5 +1,5 @@
 import org.http4k.server.Netty
 
 fun main() {
-    Http4kBenchmarkServer(PostgresDatabase("tfb-database")).start(Netty(9000))
+    Http4kBenchmarkServer(PostgresDatabase()).start(Netty(9000))
 }

+ 3 - 3
frameworks/Kotlin/http4k/ratpack/build.gradle

@@ -1,6 +1,6 @@
 dependencies {
-    api project(":core")
-    api "org.http4k:http4k-server-ratpack:$http4k_version"
+    api(project(":core-jdbc"))
+    api("org.http4k:http4k-server-ratpack:$http4k_version")
 }
 
 apply plugin: 'application'
@@ -8,7 +8,7 @@ mainClassName = "Http4kRatpackServerKt"
 apply plugin: 'com.github.johnrengelman.shadow'
 
 shadowJar {
-    baseName = "http4k-$project.name-benchmark"
+    baseName = "http4k-benchmark"
     classifier = null
     version = null
     mergeServiceFiles()

+ 1 - 1
frameworks/Kotlin/http4k/ratpack/src/main/kotlin/Http4kRatpackServer.kt

@@ -1,5 +1,5 @@
 import org.http4k.server.Ratpack
 
 fun main() {
-    Http4kBenchmarkServer(PostgresDatabase("tfb-database")).start(Ratpack(9000))
+    Http4kBenchmarkServer(PostgresDatabase()).start(Ratpack(9000))
 }

+ 5 - 0
frameworks/Kotlin/http4k/settings.gradle

@@ -1,8 +1,13 @@
 rootProject.name = 'http4k-benchmark'
 include 'core'
+include 'core-jdbc'
+include 'core-pgclient'
 include 'apache'
 include 'apache4'
+include 'graalvm'
 include 'jetty'
+include 'jettyloom-jdbc'
+include 'jettyloom-pgclient'
 include 'ktorcio'
 include 'ktornetty'
 include 'netty'

+ 2 - 2
frameworks/Kotlin/http4k/sunhttp/build.gradle

@@ -1,5 +1,5 @@
 dependencies {
-    api project(":core")
+    api(project(":core-jdbc"))
 }
 
 apply plugin: 'application'
@@ -7,7 +7,7 @@ mainClassName = "Http4kSunHttpServerKt"
 apply plugin: 'com.github.johnrengelman.shadow'
 
 shadowJar {
-    baseName = "http4k-$project.name-benchmark"
+    baseName = "http4k-benchmark"
     classifier = null
     version = null
     mergeServiceFiles()

+ 1 - 1
frameworks/Kotlin/http4k/sunhttp/src/main/kotlin/Http4kSunHttpServer.kt

@@ -1,5 +1,5 @@
 import org.http4k.server.SunHttp
 
 fun main() {
-    Http4kBenchmarkServer(PostgresDatabase("tfb-database")).start(SunHttp(9000))
+    Http4kBenchmarkServer(PostgresDatabase()).start(SunHttp(9000))
 }

+ 3 - 3
frameworks/Kotlin/http4k/undertow/build.gradle

@@ -1,6 +1,6 @@
 dependencies {
-    api project(":core")
-    api "org.http4k:http4k-server-undertow:$http4k_version"
+    api(project(":core-jdbc"))
+    api("org.http4k:http4k-server-undertow:$http4k_version")
 }
 
 apply plugin: 'application'
@@ -8,7 +8,7 @@ mainClassName = "Http4kUndertowServerKt"
 apply plugin: 'com.github.johnrengelman.shadow'
 
 shadowJar {
-    baseName = "http4k-$project.name-benchmark"
+    baseName = "http4k-benchmark"
     classifier = null
     version = null
     mergeServiceFiles()

+ 1 - 1
frameworks/Kotlin/http4k/undertow/src/main/kotlin/Http4kUndertowServer.kt

@@ -1,5 +1,5 @@
 import org.http4k.server.Undertow
 
 fun main() {
-    Http4kBenchmarkServer(PostgresDatabase("tfb-database")).start(Undertow(9000))
+    Http4kBenchmarkServer(PostgresDatabase()).start(Undertow(9000))
 }