-
Notifications
You must be signed in to change notification settings - Fork 120
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #345 from kubukoz/cats-effect
Add cats-effect to the core module, remove modes
- Loading branch information
Showing
49 changed files
with
724 additions
and
1,235 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,6 @@ | ||
sudo: false | ||
language: scala | ||
scala: | ||
- 2.11.12 | ||
- 2.13.1 | ||
- 2.12.10 | ||
jdk: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 39 additions & 35 deletions
74
modules/caffeine/src/main/scala/scalacache/caffeine/CaffeineCache.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,79 +1,83 @@ | ||
package scalacache.caffeine | ||
|
||
import java.time.temporal.ChronoUnit | ||
import java.time.{Clock, Instant} | ||
import java.time.{Instant} | ||
|
||
import com.github.benmanes.caffeine.cache.{Caffeine, Cache => CCache} | ||
|
||
import cats.effect.Clock | ||
import scalacache.logging.Logger | ||
import scalacache.{AbstractCache, CacheConfig, Entry, Mode} | ||
import scalacache.{AbstractCache, CacheConfig, Entry} | ||
import scala.concurrent.duration.Duration | ||
import scala.language.higherKinds | ||
import cats.effect.Sync | ||
import java.util.concurrent.TimeUnit | ||
import cats.implicits._ | ||
import cats.MonadError | ||
|
||
/* | ||
* Thin wrapper around Caffeine. | ||
* | ||
* This cache implementation is synchronous. | ||
*/ | ||
class CaffeineCache[V](val underlying: CCache[String, Entry[V]])( | ||
class CaffeineCache[F[_]: Sync, V](val underlying: CCache[String, Entry[V]])( | ||
implicit val config: CacheConfig, | ||
clock: Clock = Clock.systemUTC() | ||
) extends AbstractCache[V] { | ||
clock: Clock[F] | ||
) extends AbstractCache[F, V] { | ||
protected val F: Sync[F] = Sync[F] | ||
|
||
override protected final val logger = Logger.getLogger(getClass.getName) | ||
|
||
def doGet[F[_]](key: String)(implicit mode: Mode[F]): F[Option[V]] = { | ||
mode.M.delay { | ||
val entry = underlying.getIfPresent(key) | ||
val result = { | ||
if (entry == null || entry.isExpired) | ||
None | ||
else | ||
Some(entry.value) | ||
def doGet(key: String): F[Option[V]] = { | ||
F.delay { | ||
Option(underlying.getIfPresent(key)) | ||
} | ||
.flatMap(_.filterA(Entry.isExpired[F, V])) | ||
.map(_.map(_.value)) | ||
.flatTap { result => | ||
logCacheHitOrMiss(key, result) | ||
} | ||
logCacheHitOrMiss(key, result) | ||
result | ||
} | ||
} | ||
|
||
def doPut[F[_]](key: String, value: V, ttl: Option[Duration])(implicit mode: Mode[F]): F[Any] = { | ||
mode.M.delay { | ||
val entry = Entry(value, ttl.map(toExpiryTime)) | ||
underlying.put(key, entry) | ||
logCachePut(key, ttl) | ||
def doPut(key: String, value: V, ttl: Option[Duration]): F[Unit] = | ||
ttl.traverse(toExpiryTime).flatMap { expiry => | ||
F.delay { | ||
val entry = Entry(value, expiry) | ||
underlying.put(key, entry) | ||
} *> logCachePut(key, ttl) | ||
} | ||
} | ||
|
||
override def doRemove[F[_]](key: String)(implicit mode: Mode[F]): F[Any] = | ||
mode.M.delay(underlying.invalidate(key)) | ||
override def doRemove(key: String): F[Unit] = | ||
F.delay(underlying.invalidate(key)) | ||
|
||
override def doRemoveAll[F[_]]()(implicit mode: Mode[F]): F[Any] = | ||
mode.M.delay(underlying.invalidateAll()) | ||
override def doRemoveAll(): F[Unit] = | ||
F.delay(underlying.invalidateAll()) | ||
|
||
override def close[F[_]]()(implicit mode: Mode[F]): F[Any] = { | ||
override def close: F[Unit] = { | ||
// Nothing to do | ||
mode.M.pure(()) | ||
F.unit | ||
} | ||
|
||
private def toExpiryTime(ttl: Duration): Instant = | ||
Instant.now(clock).plus(ttl.toMillis, ChronoUnit.MILLIS) | ||
private def toExpiryTime(ttl: Duration): F[Instant] = | ||
clock.monotonic(TimeUnit.MILLISECONDS).map(Instant.ofEpochMilli(_).plusMillis(ttl.toMillis)) | ||
|
||
} | ||
|
||
object CaffeineCache { | ||
|
||
/** | ||
* Create a new Caffeine cache | ||
* Create a new Caffeine cache. | ||
*/ | ||
def apply[V](implicit config: CacheConfig): CaffeineCache[V] = | ||
apply(Caffeine.newBuilder().build[String, Entry[V]]()) | ||
def apply[F[_]: Sync: Clock, V](implicit config: CacheConfig): F[CaffeineCache[F, V]] = | ||
Sync[F].delay(Caffeine.newBuilder().build[String, Entry[V]]()).map(apply(_)) | ||
|
||
/** | ||
* Create a new cache utilizing the given underlying Caffeine cache. | ||
* | ||
* @param underlying a Caffeine cache | ||
*/ | ||
def apply[V](underlying: CCache[String, Entry[V]])(implicit config: CacheConfig): CaffeineCache[V] = | ||
def apply[F[_]: Sync: Clock, V]( | ||
underlying: CCache[String, Entry[V]] | ||
)(implicit config: CacheConfig): CaffeineCache[F, V] = | ||
new CaffeineCache(underlying) | ||
|
||
} |
Oops, something went wrong.