Browse Source

http4k - tweaks to database code. reduce pool size (#4385)

* http4k - tweaks to database. reduce pool size to match processors * 2

* added missing call to next()
David Denton 6 years ago
parent
commit
56a0ccf024
1 changed files with 52 additions and 54 deletions
  1. 52 54
      frameworks/Kotlin/http4k/core/src/main/kotlin/Database.kt

+ 52 - 54
frameworks/Kotlin/http4k/core/src/main/kotlin/Database.kt

@@ -9,14 +9,12 @@ 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.*
+import java.util.Random
 import java.util.concurrent.CompletableFuture
 import javax.sql.DataSource
 
-
 interface Database {
-    fun findWorld(): JsonNode?
+    fun findWorld(): JsonNode
     fun findWorlds(count: Int): List<JsonNode>
     fun updateWorlds(count: Int): List<JsonNode>
     fun fortunes(): List<Fortune>
@@ -29,11 +27,11 @@ class PostgresDatabase private constructor(private val dataSource: DataSource) :
     }
 
     override fun findWorlds(count: Int) = withConnection {
-        (1..count).mapNotNull { findWorld(randomWorld()) }
+        (1..count).map { findWorld(randomWorld()) }
     }
 
     override fun updateWorlds(count: Int) = withConnection {
-        (1..count).mapNotNull {
+        (1..count).map {
             val id = randomWorld()
             updateWorld(id)
             findWorld(id)
@@ -47,7 +45,15 @@ class PostgresDatabase private constructor(private val dataSource: DataSource) :
     }
 
     override fun fortunes() = withConnection {
-        val original = withStatement("select * from fortune") { executeQuery().toResultsList { Fortune(getInt(1), getString(2)) } }
+        val original = withStatement("select * from fortune") {
+            with(executeQuery()) {
+                mutableListOf<Fortune>().apply {
+                    while (next()) {
+                        add(Fortune(getInt(1), getString(2)))
+                    }
+                }
+            }
+        }
         (original + Fortune(0, "Additional fortune added at request time.")).sortedBy { it.message }
     }
 
@@ -57,49 +63,41 @@ class PostgresDatabase private constructor(private val dataSource: DataSource) :
                 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
+                    "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 = Runtime.getRuntime().availableProcessors() * 2
                 HikariDataSource(this)
             }
             return PostgresDatabase(dataSource)
         }
     }
 
-    private fun <T> withConnection(fn: Connection.() -> T): T = dataSource.connection.use(fn)
+    private inline fun <T> withConnection(fn: Connection.() -> T): T = dataSource.connection.use(fn)
 
-    private fun <T> Connection.withStatement(stmt: String, fn: PreparedStatement.() -> T): T = prepareStatement(stmt).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")))
-                }.firstOrNull()
-            }
-
-    private fun <T> ResultSet.toResultsList(fn: ResultSet.() -> T): List<T> =
-            use {
-                mutableListOf<T>().apply {
-                    while (next()) {
-                        add(fn(this@toResultsList))
-                    }
-                }
+        withStatement("SELECT * FROM world WHERE id = ?") {
+            setInt(1, id)
+            with(executeQuery()) {
+                next()
+                obj("id" to number(getInt("id")), "randomNumber" to number(getInt("randomNumber")))
             }
+        }
 }
 
 class ReactivePostgresDatabase private constructor(private val db: PgPool) : Database {
@@ -111,15 +109,15 @@ class ReactivePostgresDatabase private constructor(private val db: PgPool) : Dat
                 port = 5432
                 user = "benchmarkdbuser"
                 password = "benchmarkdbpass"
-                maxSize = 100
+                maxSize = Runtime.getRuntime().availableProcessors() * 2
                 cachePreparedStatements = true
             }
             return ReactivePostgresDatabase(pool(PgPoolOptions(options)))
         }
     }
 
-    override fun findWorld(): JsonNode? {
-        val deferred = CompletableFuture<JsonNode?>()
+    override fun findWorld(): JsonNode {
+        val deferred = CompletableFuture<JsonNode>()
         db.preparedQuery("SELECT id, randomnumber from WORLD where id=$1", Tuple.of(randomWorld())) {
             with(it.result().first()) {
                 deferred.complete(obj("id" to number(getInteger(0)), "randomNumber" to number(getInteger(1))))
@@ -147,20 +145,20 @@ class ReactivePostgresDatabase private constructor(private val db: PgPool) : Dat
     override fun updateWorlds(count: Int): List<JsonNode> {
         val deferred = CompletableFuture<List<JsonNode>>()
         val worlds = mutableListOf<Tuple>()
-            (1..count).forEach {
-                db.preparedQuery("SELECT id from WORLD where id=$1", Tuple.of(randomWorld())) { ar ->
-                    with(ar.result().first()) {
-                        worlds.add(Tuple.of(getInteger(0), randomWorld()))
-
-                        if (worlds.size == count) {
-                            db.preparedBatch("UPDATE world SET randomnumber=$1 WHERE id=$2", worlds) {
-                                deferred.complete(worlds.map {
-                                    obj("id" to number(it.getInteger(0)), "randomNumber" to number(it.getInteger(1)))
-                                })
-                            }
+        (1..count).forEach {
+            db.preparedQuery("SELECT id from WORLD where id=$1", Tuple.of(randomWorld())) { ar ->
+                with(ar.result().first()) {
+                    worlds.add(Tuple.of(getInteger(0), randomWorld()))
+
+                    if (worlds.size == count) {
+                        db.preparedBatch("UPDATE world SET randomnumber=$1 WHERE id=$2", worlds) {
+                            deferred.complete(worlds.map {
+                                obj("id" to number(it.getInteger(0)), "randomNumber" to number(it.getInteger(1)))
+                            })
                         }
                     }
                 }
+            }
         }
         return deferred.get()
     }