1
1
package io .chrisdavenport .mules
2
2
3
3
import cats .effect ._
4
- import cats .effect .concurrent ._
5
4
import cats .effect .implicits ._
6
5
import cats .implicits ._
7
- import scala .concurrent .duration ._
8
6
import scala .collection .immutable .Map
9
7
10
8
import io .chrisdavenport .mapref .MapRef
@@ -37,19 +35,19 @@ final class DispatchOneCache[F[_], K, V] private[DispatchOneCache] (
37
35
private val purgeExpiredEntries : Long => F [List [K ]] =
38
36
purgeExpiredEntriesOpt.getOrElse(purgeExpiredEntriesDefault)
39
37
40
- private val emptyFV = F .pure(Option .empty[TryableDeferred [F , Either [Throwable , V ]]])
38
+ private val emptyFV = F .pure(Option .empty[Deferred [F , Either [Throwable , V ]]])
41
39
42
- private val createEmptyIfUnset : K => F [Option [TryableDeferred [F , Either [Throwable , V ]]]] =
43
- k => Deferred .tryable [F , Either [Throwable , V ]].flatMap{deferred =>
44
- C .monotonic( NANOSECONDS ) .flatMap{ now =>
45
- val timeout = defaultExpiration.map(ts => TimeSpec .unsafeFromNanos(now + ts.nanos))
40
+ private val createEmptyIfUnset : K => F [Option [Deferred [F , Either [Throwable , V ]]]] =
41
+ k => Deferred [F , Either [Throwable , V ]].flatMap{deferred =>
42
+ C .monotonic.flatMap{ now =>
43
+ val timeout = defaultExpiration.map(ts => TimeSpec .unsafeFromNanos(now.toNanos + ts.nanos))
46
44
mapRef(k).modify{
47
45
case None => (DispatchOneCacheItem [F , V ](deferred, timeout).some, deferred.some)
48
46
case s@ Some (_) => (s, None )
49
47
}}
50
48
}
51
49
52
- private val updateIfFailedThenCreate : (K , DispatchOneCacheItem [F , V ]) => F [Option [TryableDeferred [F , Either [Throwable , V ]]]] =
50
+ private val updateIfFailedThenCreate : (K , DispatchOneCacheItem [F , V ]) => F [Option [Deferred [F , Either [Throwable , V ]]]] =
53
51
(k, cacheItem) => cacheItem.item.tryGet.flatMap{
54
52
case Some (Left (_)) =>
55
53
mapRef(k).modify{
@@ -72,8 +70,8 @@ final class DispatchOneCache[F[_], K, V] private[DispatchOneCache] (
72
70
maybeDeferred.bracketCase(_.traverse_{ deferred =>
73
71
action(k).attempt.flatMap(e => deferred.complete(e).attempt.void)
74
72
}){
75
- case (Some (deferred), ExitCase .Canceled ) => deferred.complete(CancelationDuringDispatchOneCacheInsertProcessing .asLeft).attempt.void
76
- case (Some (deferred), ExitCase . Error (e)) => deferred.complete(e.asLeft).attempt.void
73
+ case (Some (deferred), Outcome .Canceled () ) => deferred.complete(CancelationDuringDispatchOneCacheInsertProcessing .asLeft).attempt.void
74
+ case (Some (deferred), Outcome . Errored (e)) => deferred.complete(e.asLeft).attempt.void
77
75
case _ => F .unit
78
76
}
79
77
}
@@ -84,11 +82,11 @@ final class DispatchOneCache[F[_], K, V] private[DispatchOneCache] (
84
82
* gets the value in the system
85
83
**/
86
84
def lookupOrLoad (k : K , action : K => F [V ]): F [V ] = {
87
- C .monotonic( NANOSECONDS )
85
+ C .monotonic
88
86
.flatMap{now =>
89
87
mapRef(k).modify[Option [DispatchOneCacheItem [F , V ]]]{
90
88
case s@ Some (value) =>
91
- if (DispatchOneCache .isExpired(now, value)){
89
+ if (DispatchOneCache .isExpired(now.toNanos , value)){
92
90
(None , None )
93
91
} else {
94
92
(s, s)
@@ -108,22 +106,22 @@ final class DispatchOneCache[F[_], K, V] private[DispatchOneCache] (
108
106
109
107
def insertWith (k : K , action : K => F [V ]): F [Unit ] = {
110
108
for {
111
- defer <- Deferred .tryable [F , Either [Throwable , V ]]
112
- now <- Clock [F ].monotonic( NANOSECONDS )
113
- item = DispatchOneCacheItem (defer, defaultExpiration.map(spec => TimeSpec .unsafeFromNanos(now + spec.nanos))).some
109
+ defer <- Deferred [F , Either [Throwable , V ]]
110
+ now <- Clock [F ].monotonic
111
+ item = DispatchOneCacheItem (defer, defaultExpiration.map(spec => TimeSpec .unsafeFromNanos(now.toNanos + spec.nanos))).some
114
112
out <- mapRef(k).getAndSet(item)
115
113
.bracketCase{oldDeferOpt =>
116
114
action(k).flatMap[Unit ]{ a =>
117
115
val set = a.asRight
118
116
oldDeferOpt.traverse_(oldDefer => oldDefer.item.complete(set)).attempt >>
119
- defer.complete(set)
117
+ defer.complete(set).void
120
118
}
121
119
}{
122
- case (_, ExitCase . Completed ) => F .unit
123
- case (oldItem, ExitCase .Canceled ) =>
120
+ case (_, Outcome . Succeeded (_) ) => F .unit
121
+ case (oldItem, Outcome .Canceled () ) =>
124
122
val set = CancelationDuringDispatchOneCacheInsertProcessing .asLeft
125
123
oldItem.traverse_(_.item.complete(set)).attempt >> defer.complete(set).attempt.void
126
- case (oldItem, ExitCase . Error (e)) =>
124
+ case (oldItem, Outcome . Errored (e)) =>
127
125
val set = e.asLeft
128
126
oldItem.traverse_(_.item.complete(set)).attempt >> defer.complete(set).attempt.void
129
127
}
@@ -134,11 +132,11 @@ final class DispatchOneCache[F[_], K, V] private[DispatchOneCache] (
134
132
* Overrides any background insert
135
133
**/
136
134
def insert (k : K , v : V ): F [Unit ] = for {
137
- defered <- Deferred .tryable [F , Either [Throwable , V ]]
135
+ defered <- Deferred [F , Either [Throwable , V ]]
138
136
setAs = v.asRight
139
137
_ <- defered.complete(setAs)
140
- now <- C .monotonic( NANOSECONDS )
141
- item = DispatchOneCacheItem (defered, defaultExpiration.map(spec => TimeSpec .unsafeFromNanos(now + spec.nanos))).some
138
+ now <- C .monotonic
139
+ item = DispatchOneCacheItem (defered, defaultExpiration.map(spec => TimeSpec .unsafeFromNanos(now.toNanos + spec.nanos))).some
142
140
action <- mapRef(k).modify{
143
141
case None =>
144
142
(item, F .unit)
@@ -153,11 +151,11 @@ final class DispatchOneCache[F[_], K, V] private[DispatchOneCache] (
153
151
* Overrides any background insert
154
152
**/
155
153
def insertWithTimeout (optionTimeout : Option [TimeSpec ])(k : K , v : V ): F [Unit ] = for {
156
- defered <- Deferred .tryable [F , Either [Throwable , V ]]
154
+ defered <- Deferred [F , Either [Throwable , V ]]
157
155
setAs = v.asRight
158
156
_ <- defered.complete(setAs)
159
- now <- C .monotonic( NANOSECONDS )
160
- item = DispatchOneCacheItem (defered, optionTimeout.map(spec => TimeSpec .unsafeFromNanos(now + spec.nanos))).some
157
+ now <- C .monotonic
158
+ item = DispatchOneCacheItem (defered, optionTimeout.map(spec => TimeSpec .unsafeFromNanos(now.toNanos + spec.nanos))).some
161
159
action <- mapRef(k).modify{
162
160
case None =>
163
161
(item, F .unit)
@@ -168,11 +166,11 @@ final class DispatchOneCache[F[_], K, V] private[DispatchOneCache] (
168
166
} yield out
169
167
170
168
def lookup (k : K ): F [Option [V ]] = {
171
- C .monotonic( NANOSECONDS )
169
+ C .monotonic
172
170
.flatMap{now =>
173
171
mapRef(k).modify[Option [DispatchOneCacheItem [F , V ]]]{
174
172
case s@ Some (value) =>
175
- if (DispatchOneCache .isExpired(now, value)){
173
+ if (DispatchOneCache .isExpired(now.toNanos , value)){
176
174
(None , None )
177
175
} else {
178
176
(s, s)
@@ -208,16 +206,16 @@ final class DispatchOneCache[F[_], K, V] private[DispatchOneCache] (
208
206
**/
209
207
def purgeExpired : F [Unit ] = {
210
208
for {
211
- now <- C .monotonic( NANOSECONDS )
212
- _ <- purgeExpiredEntries(now)
209
+ now <- C .monotonic
210
+ _ <- purgeExpiredEntries(now.toNanos )
213
211
} yield ()
214
212
}
215
213
216
214
}
217
215
218
216
object DispatchOneCache {
219
217
private case class DispatchOneCacheItem [F [_], A ](
220
- item : TryableDeferred [F , Either [Throwable , A ]],
218
+ item : Deferred [F , Either [Throwable , A ]],
221
219
itemExpiration : Option [TimeSpec ]
222
220
)
223
221
private case object CancelationDuringDispatchOneCacheInsertProcessing extends scala.util.control.NoStackTrace
@@ -231,13 +229,13 @@ object DispatchOneCache {
231
229
*
232
230
* @return an `Resource[F, Unit]` that will keep removing expired entries in the background.
233
231
**/
234
- def liftToAuto [F [_]: Concurrent : Timer , K , V ](
232
+ def liftToAuto [F [_]: Temporal , K , V ](
235
233
DispatchOneCache : DispatchOneCache [F , K , V ],
236
234
checkOnExpirationsEvery : TimeSpec
237
235
): Resource [F , Unit ] = {
238
236
def runExpiration (cache : DispatchOneCache [F , K , V ]): F [Unit ] = {
239
237
val check = TimeSpec .toDuration(checkOnExpirationsEvery)
240
- Timer [F ].sleep(check) >> cache.purgeExpired >> runExpiration(cache)
238
+ Temporal [F ].sleep(check) >> cache.purgeExpired >> runExpiration(cache)
241
239
}
242
240
243
241
Resource .make(runExpiration(DispatchOneCache ).start)(_.cancel).void
@@ -248,7 +246,7 @@ object DispatchOneCache {
248
246
*
249
247
* If the specified default expiration value is None, items inserted by insert will never expire.
250
248
**/
251
- def ofSingleImmutableMap [F [_]: Concurrent : Clock , K , V ](
249
+ def ofSingleImmutableMap [F [_]: Async , K , V ](
252
250
defaultExpiration : Option [TimeSpec ]
253
251
): F [DispatchOneCache [F , K , V ]] =
254
252
Ref .of[F , Map [K , DispatchOneCacheItem [F , V ]]](Map .empty[K , DispatchOneCacheItem [F , V ]])
@@ -258,7 +256,7 @@ object DispatchOneCache {
258
256
defaultExpiration
259
257
))
260
258
261
- def ofShardedImmutableMap [F [_]: Concurrent : Clock , K , V ](
259
+ def ofShardedImmutableMap [F [_]: Async , K , V ](
262
260
shardCount : Int ,
263
261
defaultExpiration : Option [TimeSpec ]
264
262
): F [DispatchOneCache [F , K , V ]] =
@@ -270,7 +268,7 @@ object DispatchOneCache {
270
268
)
271
269
}
272
270
273
- def ofConcurrentHashMap [F [_]: Concurrent : Clock , K , V ](
271
+ def ofConcurrentHashMap [F [_]: Async , K , V ](
274
272
defaultExpiration : Option [TimeSpec ],
275
273
initialCapacity : Int = 16 ,
276
274
loadFactor : Float = 0.75f ,
0 commit comments