Skip to content

Commit

Permalink
Merge pull request #439 from bjaglin/softreference
Browse files Browse the repository at this point in the history
allow eviction of cached Scalafix instances
  • Loading branch information
bjaglin authored Oct 4, 2024
2 parents 7bfaeb2 + 847ce83 commit d2c99b3
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 35 deletions.
36 changes: 15 additions & 21 deletions src/main/scala/scalafix/internal/sbt/BlockingCache.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,26 @@ package scalafix.internal.sbt

import java.{util => ju}

import scala.util.Try
import java.lang.ref.SoftReference

/** A basic thread-safe cache without any eviction. */
/** A basic thread-safe cache with arbitrary eviction on GC pressure. */
class BlockingCache[K, V] {

private val underlying = new ju.concurrent.ConcurrentHashMap[K, V]

private case class SkipUpdate(prev: V) extends Exception
private val underlying =
new ju.concurrent.ConcurrentHashMap[K, SoftReference[V]]

// Evaluations of `transform` are guaranteed to be sequential for the same key
def compute(key: K, transform: Option[V] => Option[V]): V = {
Try(
underlying.compute(
key,
new ju.function.BiFunction[K, V, V] {
override def apply(key: K, prev: V): V = {
transform(Option(prev)).getOrElse(throw SkipUpdate(prev))
}
}
)
).fold(
{
case SkipUpdate(prev) => prev
case ex => throw ex
},
identity
def compute(key: K, transform: Option[V] => V): V = {
// keep the result in a strong reference to avoid eviction
// just after executing wrapped compute()
var result: V = null.asInstanceOf[V]
underlying.compute(
key,
(_, prev: SoftReference[V]) => {
result = transform(Option(prev).flatMap(ref => Option(ref.get)))
new SoftReference(result)
}
)
result
}
}
24 changes: 10 additions & 14 deletions src/main/scala/scalafix/internal/sbt/ScalafixInterface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ object ScalafixInterface {
None
),
{
case Some(_) =>
case Some(v) =>
// cache hit, don't update
None
v
case None =>
// cache miss, resolve scalafix artifacts and classload them
if (scalafixScalaMajorMinorVersion == "2.11")
Expand All @@ -181,11 +181,9 @@ object ScalafixInterface {
)
)

Some(
(
new ScalafixInterface(scalafixArguments).withArgs(printStream),
Nil
)
(
new ScalafixInterface(scalafixArguments).withArgs(printStream),
Nil
)
}
)
Expand All @@ -201,16 +199,14 @@ object ScalafixInterface {
Some(toolClasspath)
),
{
case Some((_, oldStamps)) if (currentStamps == oldStamps) =>
case Some(v @ (_, oldStamps)) if (currentStamps == oldStamps) =>
// cache hit, don't update
None
v
case _ =>
// cache miss or stale stamps, resolve custom rules artifacts and classload them
Some(
(
buildinRulesInterface.withArgs(toolClasspath),
currentStamps
)
(
buildinRulesInterface.withArgs(toolClasspath),
currentStamps
)
}
)
Expand Down

0 comments on commit d2c99b3

Please sign in to comment.