【问题标题】:Why does scala cache ask me to define the TTL twice?为什么scala缓存要求我定义TTL两次?
【发布时间】:2019-07-16 21:12:53
【问题描述】:

所以我一直在努力跟上 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 定义。 IE。驱逐和到期的概念是不相关的,并且是分开定义的?

为了解释我的意思,这里举一个 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 为 None,则计算结果为 false。最后, 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,它应该总是评估为 not found。

  1. 如果 expireAfterWrite

【问题讨论】:

    标签: scala caching


    【解决方案1】:

    codedocs 都提供了解释:

    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

    【讨论】:

    • 我更新了我的答案,在问题 1 之后包含一个部分,该部分显示了一个看似忽略 expireAfterWrite 值的实现。
    • 嗯,答案已经包含对您的更新的答案:界面意味着在构建器中您定义了默认值,并且您定义了可选覆盖;实现定义了它将如何处理这两个值,它应该使用 ttl 参数来完全覆盖 ttl,但是您可以编写自己的实现,例如选择两者中的最小值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-12
    • 2015-04-23
    • 2016-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多