首页 > 解决方案 > 为什么scala缓存要求我定义TTL两次?

问题描述

所以我一直在努力跟上 scala 缓存的速度。我正在浏览这个文档

https://cb372.github.io/scalacache/docs/

private val thisToThatCache =
   CaffeineCache(
     Caffeine.newBuilder
       .maximumSize(4096)
       .expireAfterWrite(4, TimeUnit.HOURS)
       .build[String, String)

和这个缓存调用

 import scalacache.modes.try_._
 import scala.collection.JavaConverters._

 thisToThatCache.caching(thisStr)(ttl = 4.hours)(
    fetchThatForGivenThis(thisStr)
 )

请注意,我已经定义了两次 TTL,一次在缓存调用中使用 4.hours,另一次基于 4 TimeUnit.Hours

这有点奇怪,所以我开始研究 CaffeineCache 的实现

我看着这个

https://github.com/cb372/scalacache/blob/433d07ddb1249d7e6ec13fe7584a3d785be8d44d/modules/caffeine/src/main/scala/scalacache/caffeine/CaffeineCache.scala#L29

而且我意识到,无论我将 expire After Write 值放在什么位置,如果缓存 ttl 值已过期(至少应该如此),getter 都会认为工件已过期。

AFAIK 底层缓存定义了驱逐。

所以我的问题是

  1. scala缓存的设计决策是什么,对TTL有两种不同的定义。即驱逐和到期的概念是不连贯的并分别定义?

为了解释我的意思 doPut https://github.com/cb372/scalacache/blob/433d07ddb1249d7e6ec13fe7584a3d785be8d44d/modules/caffeine/src/main/scala/scalacache/caffeine/CaffeineCache.scala#L42的具体示例在这里创建了一个 Entry 对象并将其放入。条目定义 isExpired https://github.com/cb372/scalacache/blob/dd7f9988b3b1cab20ba2a9649a51a36210065607/modules/core/shared/src/main/scala/scalacache/Entry.scala#L13,如果expiresAt 是无。最后是 doGet:https ://github.com/cb372/scalacache/blob/433d07ddb1249d7e6ec13fe7584a3d785be8d44d/modules/caffeine/src/main/scala/scalacache/caffeine/CaffeineCache.scala#L29方法检查其是否过期(如果之前的键的 doPut 已 expiredAt 为 None,则它评估为 false)并返回 None,因为它被认为已过期。请注意,它没有咨询 expireAfter... 超时。因此,如果我通过 None,它应该始终评估为未找到。

  1. 如果 expireAfterWrite < ttl 在缓存中的行为是什么。到期是要遵守 expireAfterWrite 还是取决于实现(即底层缓存仅在缓存达到有界大小时才延迟驱逐对象)?

标签: scalacaching

解决方案


代码文档都提供了解释:

caching("benjamin")(ttl = None)

ttl是一个Option[Duration],所以它应该定义在

expireAfterWrite(4, TimeUnit.HOURS)

同时,当您使用时:

caching("benjamin")(ttl = 4.hours) // implicit conversion to Some(4.hours)

您可以覆盖特定值的默认值。实现细节取决于实现:

// abstract def that need to be implemented by particular cache implemetation
protected def doPut[F[_]](key: String, value: V, ttl: Option[Duration])(implicit mode: Mode[F]): F[Any]

正如你所看到的,它接收到可选的 ttl,它可以用它做任何它想做的事情(甚至忽略)。默认值必须在其他地方提供,我们可以在文档中看到,这就是 builder 使用expireAfterWrite.

长话短说,您不必提供 ttl 两次。None如果您不想覆盖该值,请通过。


推荐阅读