<commit_before>package lila.memo

import com.github.benmanes.caffeine.cache._
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit
import scala.concurrent.duration._

/**
 * A synchronous cache from asynchronous computations.
 * It will attempt to serve cached responses synchronously.
 * If none is available, it starts an async computation,
 * and either waits for the result or serves a default value.
 */
final class Syncache[K, V](
    name: String,
    compute: K => Fu[V],
    default: K => V,
    strategy: Syncache.Strategy,
    expireAfter: Syncache.ExpireAfter,
    logger: lila.log.Logger,
    resultTimeout: FiniteDuration = 5 seconds)(implicit system: akka.actor.ActorSystem) {

  import Syncache._

  // ongoing async computations
  private val chm = new ConcurrentHashMap[K, Fu[V]]

  // sync cached values
  private val cache: Cache[K, V] = {
    val b1 = Caffeine.newBuilder().asInstanceOf[Caffeine[K, V]]
    val b2 = expireAfter match {
      case ExpireAfterAccess(duration) => b1.expireAfterAccess(duration.toMillis, TimeUnit.MILLISECONDS)
      case ExpireAfterWrite(duration)  => b1.expireAfterWrite(duration.toMillis, TimeUnit.MILLISECONDS)
    }
    b2.build[K, V]()
  }

  // get the value synchronously, might block depending on strategy
  def sync(k: K): V = {
    val v = cache getIfPresent k
    if (v != null) v
    else {
      // println(s"*** miss $name $k")
      // Thread.dumpStack()
      incMiss()
      chm.computeIfAbsent(k, loadFunction)
      strategy match {
        case NeverWait            => default(k)
        case AlwaysWait(duration) => waitForResult(k, duration)
        case WaitAfterUptime(duration, uptime) =>
          if (lila.common.PlayApp startedSinceSeconds uptime) waitForResult(k, duration)
          else default(k)
      }
    }
  }

  // get the value asynchronously, never blocks (preferred)
  def async(k: K): Fu[V] = {
    val v = cache getIfPresent k
    if (v != null) fuccess(v)
    else {
      chm.computeIfAbsent(k, loadFunction)
      chm get k
    }
  }

  def invalidate(k: K): Unit = cache invalidate k

  def preloadOne(k: K): Funit =
    if (cache.getIfPresent(k) == null) {
      // println(s"*** preload $name $k")
      incPreload()
      chm.computeIfAbsent(k, loadFunction)
      chm.get(k).void
    }
    else funit<commit_msg>avoid calling chm.get in Syncache.preloadOne<commit_after>package lila.memo

import com.github.benmanes.caffeine.cache._
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit
import scala.concurrent.duration._

/**
 * A synchronous cache from asynchronous computations.
 * It will attempt to serve cached responses synchronously.
 * If none is available, it starts an async computation,
 * and either waits for the result or serves a default value.
 */
final class Syncache[K, V](
    name: String,
    compute: K => Fu[V],
    default: K => V,
    strategy: Syncache.Strategy,
    expireAfter: Syncache.ExpireAfter,
    logger: lila.log.Logger,
    resultTimeout: FiniteDuration = 5 seconds)(implicit system: akka.actor.ActorSystem) {

  import Syncache._

  // ongoing async computations
  private val chm = new ConcurrentHashMap[K, Fu[V]]

  // sync cached values
  private val cache: Cache[K, V] = {
    val b1 = Caffeine.newBuilder().asInstanceOf[Caffeine[K, V]]
    val b2 = expireAfter match {
      case ExpireAfterAccess(duration) => b1.expireAfterAccess(duration.toMillis, TimeUnit.MILLISECONDS)
      case ExpireAfterWrite(duration)  => b1.expireAfterWrite(duration.toMillis, TimeUnit.MILLISECONDS)
    }
    b2.build[K, V]()
  }

  // get the value synchronously, might block depending on strategy
  def sync(k: K): V = {
    val v = cache getIfPresent k
    if (v != null) v
    else {
      // println(s"*** miss $name $k")
      // Thread.dumpStack()
      incMiss()
      chm.computeIfAbsent(k, loadFunction)
      strategy match {
        case NeverWait            => default(k)
        case AlwaysWait(duration) => waitForResult(k, duration)
        case WaitAfterUptime(duration, uptime) =>
          if (lila.common.PlayApp startedSinceSeconds uptime) waitForResult(k, duration)
          else default(k)
      }
    }
  }

  // get the value asynchronously, never blocks (preferred)
  def async(k: K): Fu[V] = {
    val v = cache getIfPresent k
    if (v != null) fuccess(v)
    else {
      chm.computeIfAbsent(k, loadFunction)
      chm get k
    }
  }

  def invalidate(k: K): Unit = cache invalidate k

  def preloadOne(k: K): Funit =
    if (cache.getIfPresent(k) == null) {
      // println(s"*** preload $name $k")
      incPreload()
      chm.computeIfAbsent(k, loadFunction).void
    }
    else funit
{'fraction_non_alphanumeric': 0.1090561224489796, 'fraction_numerical': 0.002551020408163265, 'mean_word_length': 3.02480752780154, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3851868', 'n_tokens_mistral': 1538, 'n_tokens_neox': 1512, 'n_words': 414}