-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
142 additions
and
21 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
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
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
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
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
50 changes: 50 additions & 0 deletions
50
src/main/scala/io/findify/featury/persistence/redis/RedisPeriodicCounter.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 |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package io.findify.featury.persistence.redis | ||
|
||
import cats.effect.IO | ||
import io.findify.featury.feature.PeriodicCounter | ||
import io.findify.featury.feature.PeriodicCounter.{PeriodicCounterConfig, PeriodicCounterState} | ||
import io.findify.featury.model.{BackendError, Key, Timestamp} | ||
import redis.clients.jedis.Jedis | ||
|
||
import scala.annotation.tailrec | ||
import scala.collection.JavaConverters._ | ||
import scala.util.{Failure, Success, Try} | ||
|
||
class RedisPeriodicCounter(val config: PeriodicCounterConfig, redis: Jedis) extends PeriodicCounter { | ||
val SUFFIX = "pc" | ||
val SUFFIX_TS = "pct" | ||
import KeyCodec._ | ||
override def increment(key: Key, ts: Timestamp, value: Double): IO[Unit] = for { | ||
_ <- IO { redis.hincrByFloat(key.toRedisKey(SUFFIX), ts.toStartOfPeriod(config.period).ts.toString, value) } | ||
_ <- IO { redis.set(key.toRedisKey(SUFFIX_TS), ts.ts.toString) } | ||
} yield {} | ||
|
||
override def readState(key: Key): IO[PeriodicCounter.PeriodicCounterState] = for { | ||
responseOption <- IO { Option(redis.hgetAll(key.toRedisKey(SUFFIX))).map(_.asScala) } | ||
nowOption <- IO { Option(redis.get(key.toRedisKey(SUFFIX_TS))) } | ||
now <- nowOption match { | ||
case Some(value) => IO.fromTry(Try(java.lang.Long.parseLong(value))) | ||
case None => IO.raiseError(BackendError(s"cannot parse ts: $nowOption")) | ||
} | ||
decoded <- responseOption match { | ||
case None => IO.pure(empty()) | ||
case Some(response) => parseResponse(response.toList).map(x => PeriodicCounterState(Timestamp(now), x)) | ||
} | ||
} yield { | ||
decoded | ||
} | ||
|
||
@tailrec private def parseResponse( | ||
values: List[(String, String)], | ||
acc: List[(Timestamp, Double)] = Nil | ||
): IO[Map[Timestamp, Double]] = | ||
values match { | ||
case Nil => IO(acc.toMap) | ||
case (key, value) :: tail => | ||
(Try(java.lang.Long.parseLong(key)), Try(java.lang.Double.parseDouble(value))) match { | ||
case (Success(ts), Success(inc)) => parseResponse(tail, (Timestamp(ts) -> inc) :: acc) | ||
case (Failure(ex), _) => IO.raiseError(ex) | ||
case (_, Failure(ex)) => IO.raiseError(ex) | ||
} | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
src/main/scala/io/findify/featury/persistence/redis/RedisPersistence.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 |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package io.findify.featury.persistence.redis | ||
|
||
import cats.effect.IO | ||
import cats.effect.kernel.Resource | ||
import io.findify.featury.feature.{BoundedList, Counter, FreqEstimator, PeriodicCounter, StatsEstimator} | ||
import io.findify.featury.model.FeatureValue | ||
import io.findify.featury.persistence.{Persistence, ValueStore} | ||
import redis.clients.jedis.Jedis | ||
|
||
class RedisPersistence(val redis: Jedis) extends Persistence { | ||
override def periodicCounter(config: PeriodicCounter.PeriodicCounterConfig): PeriodicCounter = | ||
??? | ||
|
||
override def numBoundedList(config: BoundedList.BoundedListConfig): BoundedList[FeatureValue.Num] = | ||
new RedisBoundedList.RedisNumBoundedList(redis, config) | ||
|
||
override def textBoundedList(config: BoundedList.BoundedListConfig): BoundedList[FeatureValue.Text] = | ||
new RedisBoundedList.RedisTextBoundedList(redis, config) | ||
|
||
override def statsEstimator(config: StatsEstimator.StatsEstimatorConfig): StatsEstimator = | ||
new RedisStatsEstimator(config, redis) | ||
|
||
override def counter(config: Counter.CounterConfig): Counter = | ||
new RedisCounter(config, redis) | ||
|
||
override def freqEstimator(config: FreqEstimator.FreqEstimatorConfig): FreqEstimator = | ||
new RedisFreqEstimator(config, redis) | ||
|
||
override def values(): ValueStore = | ||
new RedisValues(redis) | ||
} | ||
|
||
object RedisPersistence { | ||
def resource(host: String, port: Int = 6379) = | ||
Resource.make(IO { new RedisPersistence(new Jedis(host, port)) })(redis => IO(redis.redis.close())) | ||
} |
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
9 changes: 9 additions & 0 deletions
9
src/test/scala/io/findify/featury/persistence/redis/RedisPeriodicCounterTest.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 |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package io.findify.featury.persistence.redis | ||
|
||
import cats.effect.{IO, Resource} | ||
import io.findify.featury.feature.{PeriodicCounter, PeriodicCounterSuite} | ||
|
||
class RedisPeriodicCounterTest extends PeriodicCounterSuite with RedisMock { | ||
override def makeCounter(): Resource[IO, PeriodicCounter] = | ||
Resource.make(IO(new RedisPeriodicCounter(config, redisClient)))(_ => IO.unit) | ||
} |