-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add JMX support for statement cache, and unit tests. (#1972)
JMX allows a developer to use `jconsole` to connect to the app, and introspect various metrics about it. This PR adds metrics about the `PreparedStatement` cache, and allows a developer to turn on/off at runtime on demand.
- Loading branch information
1 parent
863ac6b
commit 1fb794f
Showing
17 changed files
with
283 additions
and
129 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package core.db | ||
|
||
import core.util.HOLogger | ||
import java.sql.PreparedStatement | ||
import java.sql.SQLException | ||
import java.time.Instant | ||
import java.util.* | ||
|
||
/** | ||
* Cache for [PreparedStatement]s instances. | ||
* | ||
* | ||
* This cache tracks statistics about the various prepared statements: | ||
* | ||
* * Creation timestamp, | ||
* * Last access timestamp, | ||
* * NUmber of accesses. | ||
* | ||
* | ||
* | ||
* The cache can be disabled by setting `cachedEnabled` to `false`. When the cache | ||
* is disabled, the existing entries are closed and evicted, the stats dumped and cleared. The cache can | ||
* be enabled or disabled via JMX in development mode. By default, the cache is on. | ||
*/ | ||
class StatementCache(private val connectionManager: ConnectionManager) { | ||
var cachedEnabled = true | ||
set(enabled) { | ||
field = enabled | ||
HOLogger.instance().info(StatementCache::class.java, "Cache enabled = $enabled") | ||
if (!field) { | ||
clearCache() | ||
} | ||
} | ||
|
||
private val cache = Collections.synchronizedMap(HashMap<String, PreparedStatement?>()) | ||
|
||
val statementStats: MutableMap<String, CachedStatementStats> = Collections.synchronizedMap(HashMap()) | ||
|
||
private fun getFromCache(query: String): PreparedStatement? { | ||
if (cachedEnabled) { | ||
val statement = cache[query] | ||
if (statement != null) { | ||
val stats = statementStats[query] | ||
statementStats[query] = CachedStatementStats(stats!!.created, Instant.now(), stats.count + 1) | ||
return statement | ||
} | ||
} | ||
return null | ||
} | ||
|
||
private fun createStatement(query: String): PreparedStatement? { | ||
var statement: PreparedStatement? = null | ||
try { | ||
statement = connectionManager.connection.prepareStatement(query) | ||
if (cachedEnabled) { | ||
cache[query] = statement | ||
statementStats[query] = CachedStatementStats(Instant.now(), Instant.now(), 1) | ||
} | ||
} catch (e: SQLException) { | ||
HOLogger.instance().error( | ||
StatementCache::class.java, """Error creating statement: $query | ||
Error: ${e.message}""" | ||
) | ||
} | ||
return statement | ||
} | ||
|
||
fun getPreparedStatement(query: String): PreparedStatement? { | ||
var statement = getFromCache(query) | ||
if (statement == null) { | ||
statement = createStatement(query) | ||
} | ||
return statement | ||
} | ||
|
||
fun clearCache() { | ||
for ((key, value) in cache) { | ||
try { | ||
value!!.close() | ||
} catch (e: SQLException) { | ||
HOLogger.instance().error( | ||
StatementCache::class.java, | ||
"""Error closing prepared statement: $key | ||
${e.message}""" | ||
) | ||
} | ||
} | ||
cache.clear() | ||
dumpStats() | ||
statementStats.clear() | ||
} | ||
|
||
fun dumpStats() { | ||
for ((key, value) in statementStats) { | ||
HOLogger.instance().info(StatementCache::class.java, "$key: $value") | ||
} | ||
} | ||
|
||
@JvmRecord | ||
data class CachedStatementStats(val created: Instant, val lastAccessed: Instant, val count: Int) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package core.jmx | ||
|
||
import core.db.DBManager | ||
|
||
class StatementCacheMonitor: StatementCacheMonitorMBean { | ||
override fun getStatistics(): Map<String, String> { | ||
val connectionManager = DBManager.instance().connectionManager | ||
return connectionManager.statementCache.statementStats.map { | ||
entry -> entry.key to entry.value.toString() | ||
}.toMap() | ||
} | ||
|
||
override fun getCachedStatementCount(): Int { | ||
val connectionManager = DBManager.instance().connectionManager | ||
return connectionManager.statementCache.statementStats.size | ||
} | ||
|
||
override fun setCacheEnabled(enabled: Boolean) { | ||
val connectionManager = DBManager.instance().connectionManager | ||
connectionManager.statementCache.cachedEnabled = enabled | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package core.jmx | ||
|
||
import core.db.StatementCache | ||
|
||
interface StatementCacheMonitorMBean { | ||
fun getStatistics():Map<String, String> | ||
fun getCachedStatementCount(): Int | ||
|
||
fun setCacheEnabled(enabled: Boolean) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.