All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pl.touk.nussknacker.engine.util.cache.DefaultCache.scala Maven / Gradle / Ivy

package pl.touk.nussknacker.engine.util.cache

import com.github.benmanes.caffeine.cache
import com.github.benmanes.caffeine.cache.{Caffeine, Expiry, Ticker}

import scala.concurrent.duration.{Deadline, FiniteDuration, NANOSECONDS}

private object DefaultCacheBuilder {

  implicit class ConfiguredExpiry[K, V](config: ExpiryConfig[K, V]) extends Expiry[K, V] {

    override def expireAfterCreate(key: K, value: V, currentTime: Long): Long =
      expireOrOverrideByInfiniteCurrentDuration(
        config.expireAfterWriteFn(key, value, Deadline(currentTime, NANOSECONDS)),
        currentTime
      )

    override def expireAfterUpdate(key: K, value: V, currentTime: Long, currentDuration: Long): Long =
      expireAfterCreate(key, value, currentTime)

    override def expireAfterRead(key: K, value: V, currentTime: Long, currentDuration: Long): Long =
      expireOrPreserveCurrentDuration(
        config.expireAfterAccessFn(key, value, Deadline(currentTime, NANOSECONDS)),
        currentTime,
        currentDuration
      )

    private def expireOrOverrideByInfiniteCurrentDuration(
        expirationDeadline: Option[Deadline],
        currentTime: Long
    ): Long =
      expirationDeadline.map(_.time.toNanos - currentTime).getOrElse(Long.MaxValue)

    private def expireOrPreserveCurrentDuration(
        expirationDeadline: Option[Deadline],
        currentTime: Long,
        currentDuration: Long
    ): Long =
      expirationDeadline.map(_.time.toNanos - currentTime).getOrElse(currentDuration)

  }

  def apply[K, V](cacheConfig: CacheConfig[K, V], ticker: Ticker = Ticker.systemTicker()): Caffeine[K, V] = {
    Caffeine
      .newBuilder()
      .ticker(ticker)
      .asInstanceOf[Caffeine[K, V]]
      .maximumSize(cacheConfig.maximumSize)
      .expireAfter(cacheConfig.expiry)
  }

}

class DefaultCache[K, V](cacheConfig: CacheConfig[K, V], ticker: Ticker = Ticker.systemTicker()) extends Cache[K, V] {
  private lazy val underlying: cache.Cache[K, V] =
    DefaultCacheBuilder(cacheConfig, ticker).build()

  override def getOrCreate(key: K)(value: => V): V = {
    import scala.compat.java8.FunctionConverters._
    val result = underlying.get(key, asJavaFunction((_: K) => value))
    // we must do get to make sure that read expiration will be respected
    underlying.getIfPresent(key)
    result
  }

  override def get(key: K): Option[V] = Option(underlying.getIfPresent(key))

  override def put(key: K)(value: V): Unit = underlying.put(key, value)
}

class SingleValueCache[T](expireAfterAccess: Option[FiniteDuration], expireAfterWrite: Option[FiniteDuration]) {

  private val cache = new DefaultCache[Unit, T](CacheConfig(1, expireAfterAccess, expireAfterWrite))

  def getOrCreate(value: => T): T = cache.getOrCreate(())(value)

  def get(): Option[T] = cache.get(())

  def put(value: T): Unit = cache.put(())(value)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy