-
Notifications
You must be signed in to change notification settings - Fork 508
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Make clicking "Unknown" language do nothing. #97 * Implement user cache using embedded H2. * Separate caching to its own service #110 * Change UserProfile to be not Serializable * Fix copy-paste errors. * Replace Jackson with Gson which reduced boilerplate code by a bit. * Introduce an extension function * Remove unnecessary JsonDeserializer class. Instead, I decided to use a simple TypeAdapter in order to deserialize number into java.util.Date. * Switch back to Jackson as deserializer. * Add warning suppression. * Replace redundant creation of ObjectMapper. * Replace LocalDateTime with Instant. * Prevent multiple invocations of generateUserProfile. * Cache by lazy. * Remove unnecessary JSON deserialization from lookUpInCache. * Prevent NPE. * Update src/main/kotlin/app/CacheService.kt Co-authored-by: Sidd <[email protected]> * Revert "Prevent multiple invocations of generateUserProfile." This reverts commit 8306d92 * Remove unnecessary custom deserializer. * Rename function. UserService#lookUpInCache → selectJsonFromDb * Reduce invocations of CacheService#selectJsonFromDb. * Extract functions from duplicate code. * Update src/main/kotlin/app/CacheService.kt Co-authored-by: Sidd <[email protected]> * Remove unnecessary class UserNotLoadableException. * Remove unnecessary lazy initialization. * Change id values to lowercase in DB. follow-up change to 80154a0 * Change data type of `timestamp` from 'TIMESTAMP WITH TIME ZONE' to 'TIMESTAMP'. * Use HikariCP. * Update src/main/kotlin/app/util/HikariCpDataSource.kt Co-authored-by: Sidd <[email protected]> * Replace string concatenation with multi-line string * Replace uses of magic numbers * Remove intermediate local variable * Make CacheService have `HikariCpDataSource.connection` as its field Co-authored-by: Sidd <[email protected]>
- Loading branch information
1 parent
e815630
commit f7488ae
Showing
7 changed files
with
186 additions
and
110 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 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,86 @@ | ||
@file:Suppress("SqlResolve") | ||
|
||
package app | ||
|
||
import app.util.HikariCpDataSource | ||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper | ||
import com.fasterxml.jackson.module.kotlin.readValue | ||
import org.slf4j.LoggerFactory | ||
import java.time.Instant | ||
import java.time.temporal.ChronoUnit | ||
|
||
object CacheService { | ||
private val log = LoggerFactory.getLogger(CacheService.javaClass) | ||
private val objectMapper = jacksonObjectMapper() | ||
private val connection = HikariCpDataSource.connection | ||
|
||
private fun createTableIfAbsent() { | ||
val statement = connection.createStatement() | ||
|
||
statement.execute( | ||
""" | ||
CREATE TABLE IF NOT EXISTS userinfo ( | ||
id VARCHAR2 PRIMARY KEY, | ||
timestamp TIMESTAMP, | ||
data JSON | ||
) | ||
""".trimIndent() | ||
) | ||
} | ||
|
||
fun selectJsonFromDb(username: String): String? { | ||
createTableIfAbsent() | ||
|
||
val preparedStatement = connection.prepareStatement( | ||
""" | ||
SELECT | ||
timestamp, | ||
data | ||
FROM userinfo | ||
WHERE id = ? | ||
""".trimIndent() | ||
) | ||
preparedStatement.setString(1, username.lowercase()) | ||
|
||
val result = preparedStatement.executeQuery() | ||
result.use { | ||
// guaranteed to be at most one. | ||
if (it.next()) { | ||
val timestamp = it.getTimestamp("timestamp").toInstant() | ||
val diffInHours = ChronoUnit.HOURS.between(timestamp, Instant.now()) | ||
if (diffInHours <= 6) { | ||
val json: String? = it.getString("data") | ||
if (json != null) { | ||
log.debug("cache hit: {}", json) | ||
} | ||
|
||
return json | ||
} | ||
} | ||
} | ||
|
||
log.debug("cache miss for username: {}", username) | ||
|
||
return null | ||
} | ||
|
||
fun getUserFromJson(json: String) = objectMapper.readValue<UserProfile>(json) | ||
|
||
fun saveInCache(userProfile: UserProfile) { | ||
createTableIfAbsent() | ||
|
||
val json = objectMapper.writeValueAsString(userProfile) | ||
|
||
val preparedStatement = connection.prepareStatement( | ||
""" | ||
MERGE INTO userinfo (id, timestamp, data) KEY (id) | ||
VALUES (?, CURRENT_TIMESTAMP(), ? FORMAT JSON) | ||
""".trimIndent() | ||
) | ||
|
||
preparedStatement.setString(1, userProfile.user.login.lowercase()) | ||
preparedStatement.setString(2, json) | ||
|
||
preparedStatement.execute() | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package app | ||
|
||
import org.eclipse.egit.github.core.User | ||
|
||
data class UserProfile( | ||
val user: User, | ||
val quarterCommitCount: Map<String, Int>, | ||
val langRepoCount: Map<String, Int>, | ||
val langStarCount: Map<String, Int>, | ||
val langCommitCount: Map<String, Int>, | ||
val repoCommitCount: Map<String, Int>, | ||
val repoStarCount: Map<String, Int>, | ||
val repoCommitCountDescriptions: Map<String, String?>, | ||
val repoStarCountDescriptions: Map<String, String?> | ||
) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package app.util | ||
|
||
import com.zaxxer.hikari.HikariConfig | ||
import com.zaxxer.hikari.HikariDataSource | ||
import java.sql.Connection | ||
|
||
object HikariCpDataSource { | ||
private const val urlToDb = "jdbc:h2:mem:userinfo" | ||
|
||
private val config = HikariConfig().apply { | ||
jdbcUrl = urlToDb | ||
addDataSourceProperty("cachePrepStmts", "true") | ||
addDataSourceProperty("prepStmtCacheSize", "250") | ||
addDataSourceProperty("prepStmtCacheSqlLimit", "2048") | ||
} | ||
|
||
private var hikariDataSource = HikariDataSource(config) | ||
|
||
val connection: Connection get() = hikariDataSource.connection | ||
} |