Skip to content

Commit

Permalink
Added caching for document result Layers
Browse files Browse the repository at this point in the history
  • Loading branch information
PrinsINT committed Nov 19, 2024
1 parent 353a2bf commit 2d4b1fd
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 5 deletions.
3 changes: 3 additions & 0 deletions server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ dependencies {

// json
implementation("com.beust:klaxon:5.6")

// cache
implementation("com.github.ben-manes.caffeine:caffeine:3.1.8")
}

tasks.withType<Test> {
Expand Down
41 changes: 36 additions & 5 deletions server/src/main/kotlin/org/ivdnt/galahad/FileBackedValue.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ package org.ivdnt.galahad

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import com.github.benmanes.caffeine.cache.Cache
import com.github.benmanes.caffeine.cache.Caffeine
import com.github.benmanes.caffeine.cache.Weigher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import org.apache.logging.log4j.kotlin.Logging
import org.ivdnt.galahad.data.layer.Layer
import java.io.File
import kotlin.io.path.Path


val mapper: ObjectMapper by lazy { ObjectMapper() }
Expand Down Expand Up @@ -41,6 +46,16 @@ open class FileBackedValue<T>(
val initValue: T, // required to avoid null
) : Logging {

companion object {
/** Special cache for [Layer] objects because of their large size */
val cache: Cache<String, Layer> = Caffeine.newBuilder()
.recordStats()
.maximumWeight(100_000_000) // 100MB
// Weigher is used once at put() time
.weigher<String, Layer>(Weigher { key, value -> File(key).length().toInt() })
.build()
}

init {
file.parentFile.mkdirs()
//file.createNewFile()//
Expand All @@ -52,12 +67,24 @@ open class FileBackedValue<T>(
get() = file.lastModified()

inline fun <reified S : T>read(): T {
// It was not set yet
if( !file.exists() || file.length() == 0L ) {
// It was not set yet
return initValue
}
val bytes: ByteArray = runBlocking(Dispatchers.IO) { file.inputStream().use { it.readBytes() }}
return mapper.readValue(bytes, object : TypeReference<S>() {})

// For [Layer]s, try getting from cache
if (S::class == Layer::class) {
cache.getIfPresent(file.absolutePath)?.let { return it as T }
}

// else read from disk
val bytes: ByteArray = file.readBytes()
val result = mapper.readValue(bytes, object : TypeReference<S>() {})
// For [Layer]s, put in cache
if (S::class == Layer::class) {
cache.put(file.absolutePath, result as Layer)
}
return result
}

/**
Expand All @@ -68,13 +95,17 @@ open class FileBackedValue<T>(
* modify<Int> { oldValue++ }
*/
inline fun <reified S : T>modify( modification: (T) -> T ) {
if( !file.exists() ) {
if(!file.exists()) {
file.createNewFile()
}
// Would love to do this atomically, but for now we won't
val oldValue = read<S>()
val newValue = modification(oldValue)
val newValBytes = mapper.writeValueAsBytes(newValue)
runBlocking(Dispatchers.IO) { file.writeBytes(newValBytes)}
runBlocking(Dispatchers.IO) { file.writeBytes(newValBytes) }
// For [Layer]s, put in cache
if (S::class == Layer::class) {
cache.put(file.absolutePath, newValue as Layer)
}
}
}
17 changes: 17 additions & 0 deletions server/src/main/kotlin/org/ivdnt/galahad/app/CacheStatsReporter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.ivdnt.galahad.app

import org.springframework.scheduling.annotation.Scheduled
import org.apache.logging.log4j.kotlin.Logging
import org.ivdnt.galahad.FileBackedValue
import org.ivdnt.galahad.util.toFixed
import org.springframework.stereotype.Component
import java.util.concurrent.TimeUnit

@Component
class CacheStatsReporter : Logging {
@Scheduled(fixedDelay = 10, timeUnit = TimeUnit.MINUTES)
fun reportStats() {
val stats = FileBackedValue.cache.stats()
logger.info("Cache hit rate: ${stats.hitRate().toFixed()} [hit: ${stats.hitCount()} miss: ${stats.missCount()} evictions: ${stats.evictionCount()}]")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.scheduling.annotation.EnableScheduling
import org.springframework.web.bind.annotation.CrossOrigin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
Expand Down Expand Up @@ -96,6 +97,7 @@ fun String.runCommand(workingDir: File, timeout: Long = 60): String? {

@Configuration
@ConfigurationProperties(prefix = "")
@EnableScheduling
class Config {

lateinit var workDir: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ package org.ivdnt.galahad.util
import java.util.*

fun Float.toFixed(n: Number=3): String = String.format(Locale.ENGLISH, "%.${n}f", this)
fun Double.toFixed(n: Number=3): String = String.format(Locale.ENGLISH, "%.${n}f", this)

0 comments on commit 2d4b1fd

Please sign in to comment.