Implement version cache using scalaz Memo and guava cache builder

This commit is contained in:
Thibault Duplessis 2012-03-17 13:33:18 +01:00
parent 02ab64c0e8
commit 3b0c3d72ff
5 changed files with 66 additions and 29 deletions

View file

@ -8,14 +8,11 @@ trait Resolvers {
val iliaz = "iliaz.com" at "http://scala.iliaz.com/"
val sonatype = "sonatype" at "http://oss.sonatype.org/content/repositories/releases"
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 {
val scalaz = "org.scalaz" %% "scalaz-core" % "6.0.4"
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 salat = "com.novus" %% "salat-core" % "0.0.8-SNAPSHOT"
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 config = "com.typesafe.config" % "config" % "0.3.0"
val json = "com.codahale" %% "jerkson" % "0.5.0"
val guava = "com.google.guava" % "guava" % "11.0.1"
// benchmark
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",
version := "0.1",
scalaVersion := "2.9.1",
resolvers := Seq(iliaz, codahale, sonatype, novusS, typesafe, guice),
resolvers := Seq(iliaz, codahale, sonatype, novusS, typesafe),
libraryDependencies := Seq(scalalib),
libraryDependencies in test := Seq(specs2),
shellPrompt := {
@ -53,7 +51,7 @@ object ApplicationBuild extends Build with Resolvers with Dependencies {
) dependsOn (system)
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)
lazy val chess = Project("chess", file("chess"), settings = buildSettings).settings(

View file

@ -4,10 +4,8 @@ import com.mongodb.casbah.MongoConnection
import com.mongodb.casbah.commons.conversions.scala._
import com.typesafe.config._
import org.sedis._
import redis.clients.jedis._
import ai._
import memo._
trait SystemEnv {
@ -30,12 +28,7 @@ trait SystemEnv {
config getInt "mongo.port"
)(config getString "mongo.dbName")
def versionCache = new VersionCache(redis)
def redis = new Pool(new JedisPool(
new JedisPoolConfig(),
config getString "redis.host",
config getInt "redis.port"))
def versionMemo = new VersionMemo
}
object SystemEnv extends EnvBuilder {

View file

@ -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"
}

View 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)
}
}

View 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
}