Skip to content

Commit

Permalink
replace Caffeine cache with Guava LRU cache
Browse files Browse the repository at this point in the history
  • Loading branch information
brambg committed Apr 3, 2024
1 parent 780d2e0 commit 761a817
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 15 deletions.
1 change: 1 addition & 0 deletions common/src/main/kotlin/nl/knaw/huc/annorepo/api/classes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ data class SearchStatusSummary(
val query: HashMap<*, *>,
val startedAt: Date,
val finishedAt: Date?,
val lastAccessedAt: Date?,
val expiresAfter: Date?,
val state: String,
val containersSearched: Int,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package nl.knaw.huc.annorepo.api

import java.util.Date
import org.joda.time.Instant
import nl.knaw.huc.annorepo.resources.tools.SearchChore

object SearchChoreIndex {
Expand All @@ -12,6 +13,10 @@ object SearchChoreIndex {
index[id] = value
}

fun ping(id: String) {
index[id]?.status?.let { it.lastAccessed = Instant.now() }
}

fun purgeExpiredChores() {
val expiredChoresIds = index.entries
.asSequence()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package nl.knaw.huc.annorepo.dao
import java.util.SortedMap
import java.util.UUID
import com.fasterxml.jackson.databind.ObjectMapper
import com.github.benmanes.caffeine.cache.Cache
import com.github.benmanes.caffeine.cache.Caffeine
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
import com.google.common.cache.LoadingCache
import com.mongodb.client.MongoClient
import com.mongodb.client.MongoCollection
import com.mongodb.client.MongoDatabase
Expand All @@ -29,8 +30,10 @@ class ARContainerDAO(configuration: AnnoRepoConfiguration, client: MongoClient)
val log: Logger = LoggerFactory.getLogger(ARContainerDAO::class.java)

private val mdb: MongoDatabase = client.getDatabase(configuration.databaseName)
private val distinctValuesCache: Cache<String, List<Any>> =
Caffeine.newBuilder().maximumSize(MAX_CACHE_SIZE).build()

private val distinctValuesCache: LoadingCache<String, List<Any>> = CacheBuilder.newBuilder()
.maximumSize(MAX_CACHE_SIZE)
.build(CacheLoader.from { _: String -> null })

override fun getCollection(containerName: String): MongoCollection<Document> = mdb.getCollection(containerName)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ import jakarta.ws.rs.core.Response
import jakarta.ws.rs.core.SecurityContext
import jakarta.ws.rs.core.UriBuilder
import com.codahale.metrics.annotation.Timed
import com.github.benmanes.caffeine.cache.Cache
import com.github.benmanes.caffeine.cache.Caffeine
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
import com.google.common.cache.LoadingCache
import com.mongodb.client.MongoCollection
import com.mongodb.client.model.Aggregates
import com.mongodb.client.model.Aggregates.limit
Expand Down Expand Up @@ -82,8 +83,10 @@ class ContainerServiceResource(
private val paginationStage = limit(configuration.pageSize)
private val aggregateStageGenerator = AggregateStageGenerator(configuration)

private val queryCache: Cache<String, QueryCacheItem> =
Caffeine.newBuilder().expireAfterAccess(1, TimeUnit.HOURS).maximumSize(1000).build()
private val queryCache: LoadingCache<String, QueryCacheItem> = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterAccess(1, TimeUnit.HOURS)
.build(CacheLoader.from { _: String -> null })

@Operation(description = "Turn read-only access to this container for anonymous users on or off")
@Timed
Expand Down Expand Up @@ -416,8 +419,7 @@ class ContainerServiceResource(

private fun indexData(container: MongoCollection<Document>, containerName: String): List<IndexConfig> =
container.listIndexes()
.map { it.toMap().asIndexConfig(containerName) }
.filterNotNull()
.mapNotNull { it.toMap().asIndexConfig(containerName) }
.toList()

private fun Map<String, Any>.asIndexConfig(containerName: String): IndexConfig? {
Expand All @@ -443,8 +445,9 @@ class ContainerServiceResource(
}
}

private fun getQueryCacheItem(searchId: String): QueryCacheItem = queryCache.getIfPresent(searchId)
?: throw NotFoundException("No search results found for this search id. The search might have expired.")
private fun getQueryCacheItem(searchId: String): QueryCacheItem =
queryCache.getIfPresent(searchId)
?: throw NotFoundException("No search results found for this search id. The search might have expired.")

private fun buildAnnotationPage(
searchUri: URI, annotations: AnnotationList, page: Int, total: Int,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import nl.knaw.huc.annorepo.api.ARConst
import nl.knaw.huc.annorepo.api.ARConst.SECURITY_SCHEME_NAME
import nl.knaw.huc.annorepo.api.AnnotationPage
import nl.knaw.huc.annorepo.api.ResourcePaths.GLOBAL_SERVICES
import nl.knaw.huc.annorepo.api.ResourcePaths.SEARCH
import nl.knaw.huc.annorepo.api.ResourcePaths.STATUS
import nl.knaw.huc.annorepo.api.WebAnnotationAsMap
import nl.knaw.huc.annorepo.config.AnnoRepoConfiguration
import nl.knaw.huc.annorepo.dao.ContainerDAO
Expand Down Expand Up @@ -97,6 +99,7 @@ class GlobalServiceResource(
@QueryParam("page") page: Int = 0
): Response {
val searchChoreStatus = searchManager.getSearchChore(searchId)?.status ?: throw NotFoundException()
searchManager.ping(searchId)
return when (searchChoreStatus.state) {
SearchChore.State.DONE -> annotationPageResponse(searchChoreStatus, page, searchId)
SearchChore.State.FAILED -> serverErrorResponse(searchChoreStatus)
Expand All @@ -107,7 +110,7 @@ class GlobalServiceResource(
@Operation(description = "Get information about the given global search")
@Timed
@GET
@Path("search/{searchId}/status")
@Path("$SEARCH/{searchId}/$STATUS")
fun getSearchStatus(
@PathParam("searchId") searchId: String,
@Context context: SecurityContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ abstract class SearchChore(queryMap: HashMap<*, *>) : Runnable {
val annotationIds: MutableList<MongoDocumentId> = mutableListOf()
var startTime: Instant = Instant.now()
var endTime: Instant? = null
var lastAccessed: Instant? = null
var totalContainersToSearch: Int = 0
val containersSearched: AtomicInteger = AtomicInteger(0)
val errors: MutableList<String> = mutableListOf()
Expand All @@ -24,6 +25,7 @@ abstract class SearchChore(queryMap: HashMap<*, *>) : Runnable {
query = queryMap,
startedAt = startTime.toDate(),
finishedAt = endTime?.toDate(),
lastAccessedAt = lastAccessed?.toDate(),
expiresAfter = expirationTime(),
state = state.name,
totalContainersToSearch = totalContainersToSearch,
Expand All @@ -35,7 +37,12 @@ abstract class SearchChore(queryMap: HashMap<*, *>) : Runnable {

private val timeToLive = TimeUnit.HOURS.toMillis(1)

fun expirationTime(): Date? = endTime?.withDurationAdded(timeToLive, 1)?.toDate()
fun expirationTime(): Date? =
if (lastAccessed != null) {
lastAccessed?.withDurationAdded(timeToLive, 1)?.toDate()
} else {
endTime?.withDurationAdded(timeToLive, 1)?.toDate()
}
}

enum class State {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class SearchManager(

fun getSearchChore(id: String): SearchChore? = SearchChoreIndex[id]

fun ping(id: String) = SearchChoreIndex.ping(id)

private fun startSearchChore(chore: SearchChore): SearchChore {
SearchChoreIndex[chore.id] = chore
Thread(chore).start()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class UriFactory(private val configuration: AnnoRepoConfiguration) {
.path(containerName)
.path(ResourcePaths.SEARCH)
.path(id)
.path("info")
.path(ResourcePaths.INFO)
.build()

fun globalSearchURL(id: String): URI =
Expand Down

0 comments on commit 761a817

Please sign in to comment.