Implement version cache using scalaz Memo and guava cache builder
This commit is contained in:
parent
02ab64c0e8
commit
3b0c3d72ff
|
@ -8,14 +8,11 @@ trait Resolvers {
|
||||||
val iliaz = "iliaz.com" at "http://scala.iliaz.com/"
|
val iliaz = "iliaz.com" at "http://scala.iliaz.com/"
|
||||||
val sonatype = "sonatype" at "http://oss.sonatype.org/content/repositories/releases"
|
val sonatype = "sonatype" at "http://oss.sonatype.org/content/repositories/releases"
|
||||||
val novusS = "repo.novus snaps" at "http://repo.novus.com/snapshots/"
|
val novusS = "repo.novus snaps" at "http://repo.novus.com/snapshots/"
|
||||||
val guice = "guice-maven" at "http://guice-maven.googlecode.com/svn/trunk"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Dependencies {
|
trait Dependencies {
|
||||||
val scalaz = "org.scalaz" %% "scalaz-core" % "6.0.4"
|
val scalaz = "org.scalaz" %% "scalaz-core" % "6.0.4"
|
||||||
val specs2 = "org.specs2" %% "specs2" % "1.8.2"
|
val specs2 = "org.specs2" %% "specs2" % "1.8.2"
|
||||||
//val redis = "net.debasishg" %% "redisclient" % "2.4.2"
|
|
||||||
val redis = "org.sedis" %% "sedis" % "1.0"
|
|
||||||
val casbah = "com.mongodb.casbah" %% "casbah" % "2.1.5-1"
|
val casbah = "com.mongodb.casbah" %% "casbah" % "2.1.5-1"
|
||||||
val salat = "com.novus" %% "salat-core" % "0.0.8-SNAPSHOT"
|
val salat = "com.novus" %% "salat-core" % "0.0.8-SNAPSHOT"
|
||||||
val slf4j = "org.slf4j" % "slf4j-nop" % "1.6.4"
|
val slf4j = "org.slf4j" % "slf4j-nop" % "1.6.4"
|
||||||
|
@ -23,6 +20,7 @@ trait Dependencies {
|
||||||
val hasher = "com.roundeights" % "hasher" % "0.3" from "http://cloud.github.com/downloads/Nycto/Hasher/hasher_2.9.1-0.3.jar"
|
val hasher = "com.roundeights" % "hasher" % "0.3" from "http://cloud.github.com/downloads/Nycto/Hasher/hasher_2.9.1-0.3.jar"
|
||||||
val config = "com.typesafe.config" % "config" % "0.3.0"
|
val config = "com.typesafe.config" % "config" % "0.3.0"
|
||||||
val json = "com.codahale" %% "jerkson" % "0.5.0"
|
val json = "com.codahale" %% "jerkson" % "0.5.0"
|
||||||
|
val guava = "com.google.guava" % "guava" % "11.0.1"
|
||||||
|
|
||||||
// benchmark
|
// benchmark
|
||||||
val instrumenter = "com.google.code.java-allocation-instrumenter" % "java-allocation-instrumenter" % "2.0"
|
val instrumenter = "com.google.code.java-allocation-instrumenter" % "java-allocation-instrumenter" % "2.0"
|
||||||
|
@ -35,7 +33,7 @@ object ApplicationBuild extends Build with Resolvers with Dependencies {
|
||||||
organization := "com.github.ornicar",
|
organization := "com.github.ornicar",
|
||||||
version := "0.1",
|
version := "0.1",
|
||||||
scalaVersion := "2.9.1",
|
scalaVersion := "2.9.1",
|
||||||
resolvers := Seq(iliaz, codahale, sonatype, novusS, typesafe, guice),
|
resolvers := Seq(iliaz, codahale, sonatype, novusS, typesafe),
|
||||||
libraryDependencies := Seq(scalalib),
|
libraryDependencies := Seq(scalalib),
|
||||||
libraryDependencies in test := Seq(specs2),
|
libraryDependencies in test := Seq(specs2),
|
||||||
shellPrompt := {
|
shellPrompt := {
|
||||||
|
@ -53,7 +51,7 @@ object ApplicationBuild extends Build with Resolvers with Dependencies {
|
||||||
) dependsOn (system)
|
) dependsOn (system)
|
||||||
|
|
||||||
lazy val system = Project("system", file("system"), settings = buildSettings).settings(
|
lazy val system = Project("system", file("system"), settings = buildSettings).settings(
|
||||||
libraryDependencies ++= Seq(scalaz, config, redis, json, casbah, salat, slf4j)
|
libraryDependencies ++= Seq(scalaz, config, json, casbah, salat, guava, slf4j)
|
||||||
) dependsOn (chess)
|
) dependsOn (chess)
|
||||||
|
|
||||||
lazy val chess = Project("chess", file("chess"), settings = buildSettings).settings(
|
lazy val chess = Project("chess", file("chess"), settings = buildSettings).settings(
|
||||||
|
|
|
@ -4,10 +4,8 @@ import com.mongodb.casbah.MongoConnection
|
||||||
import com.mongodb.casbah.commons.conversions.scala._
|
import com.mongodb.casbah.commons.conversions.scala._
|
||||||
import com.typesafe.config._
|
import com.typesafe.config._
|
||||||
|
|
||||||
import org.sedis._
|
|
||||||
import redis.clients.jedis._
|
|
||||||
|
|
||||||
import ai._
|
import ai._
|
||||||
|
import memo._
|
||||||
|
|
||||||
trait SystemEnv {
|
trait SystemEnv {
|
||||||
|
|
||||||
|
@ -30,12 +28,7 @@ trait SystemEnv {
|
||||||
config getInt "mongo.port"
|
config getInt "mongo.port"
|
||||||
)(config getString "mongo.dbName")
|
)(config getString "mongo.dbName")
|
||||||
|
|
||||||
def versionCache = new VersionCache(redis)
|
def versionMemo = new VersionMemo
|
||||||
|
|
||||||
def redis = new Pool(new JedisPool(
|
|
||||||
new JedisPoolConfig(),
|
|
||||||
config getString "redis.host",
|
|
||||||
config getInt "redis.port"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object SystemEnv extends EnvBuilder {
|
object SystemEnv extends EnvBuilder {
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
package lila.system
|
|
||||||
|
|
||||||
import org.sedis._
|
|
||||||
import redis.clients.jedis._
|
|
||||||
import Dress._
|
|
||||||
|
|
||||||
final class VersionCache(pool: Pool) {
|
|
||||||
|
|
||||||
def get(gameId: String, color: Color): Option[Int] =
|
|
||||||
pool.withClient { client ⇒
|
|
||||||
client get key(gameId, color) flatMap parseIntOption
|
|
||||||
}
|
|
||||||
|
|
||||||
def key(gameId: String, color: Color) = gameId + ":" + color.letter + ":v"
|
|
||||||
}
|
|
33
system/src/main/scala/memo/Builder.scala
Normal file
33
system/src/main/scala/memo/Builder.scala
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package lila.system
|
||||||
|
package memo
|
||||||
|
|
||||||
|
import com.google.common.base.Function
|
||||||
|
import com.google.common.cache._
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import scalaz.Memo
|
||||||
|
|
||||||
|
object Builder extends scalaz.Memos {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A caching wrapper for a function (K => V),
|
||||||
|
* backed by a Cache from Google Collections.
|
||||||
|
*/
|
||||||
|
def cache[K, V](ttl: Int): Memo[K, V] = memo[K, V] { (f: (K ⇒ V)) ⇒
|
||||||
|
val map = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterAccess(ttl, TimeUnit.SECONDS)
|
||||||
|
.asInstanceOf[CacheBuilder[K, V]]
|
||||||
|
.build[K, V](f)
|
||||||
|
.asMap()
|
||||||
|
(k: K) ⇒ map.get(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit def functionToGoogleFunction[T, R](f: T ⇒ R): Function[T, R] =
|
||||||
|
new Function[T, R] {
|
||||||
|
def apply(p1: T) = f(p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit def functionToGoogleCacheLoader[T, R](f: T ⇒ R): CacheLoader[T, R] =
|
||||||
|
new CacheLoader[T, R] {
|
||||||
|
def load(p1: T) = f(p1)
|
||||||
|
}
|
||||||
|
}
|
28
system/src/main/scala/memo/VersionCache.scala
Normal file
28
system/src/main/scala/memo/VersionCache.scala
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package lila.system
|
||||||
|
package memo
|
||||||
|
|
||||||
|
import lila.chess.Color
|
||||||
|
import scalaz.Memo
|
||||||
|
|
||||||
|
final class VersionMemo {
|
||||||
|
|
||||||
|
private val memo: String ⇒ Int = Builder.cache(1800)(compute)
|
||||||
|
|
||||||
|
def get(gameId: String, color: Color): Int =
|
||||||
|
memo(toKey(gameId, color))
|
||||||
|
|
||||||
|
private def toKey(gameId: String, color: Color): String =
|
||||||
|
gameId + ":" + color.name + ":v"
|
||||||
|
|
||||||
|
private def fromKey(key: String): Option[(String, Color)] =
|
||||||
|
key.split(':').toList match {
|
||||||
|
case gameId :: cName :: "v" :: Nil ⇒ Color(cName) map { (gameId, _) }
|
||||||
|
case _ ⇒ None
|
||||||
|
}
|
||||||
|
|
||||||
|
private def compute(key: String): Int = fromKey(key) map {
|
||||||
|
case (gameId, color) ⇒ compute(gameId, color)
|
||||||
|
} getOrElse 0
|
||||||
|
|
||||||
|
private def compute(gameId: String, color: Color): Int = 33
|
||||||
|
}
|
Loading…
Reference in a new issue