working POC of server-side eval cache

eval-cache
Thibault Duplessis 2017-01-31 14:39:57 +01:00
parent ecb4f910f6
commit 02202c75ab
8 changed files with 29 additions and 24 deletions

View File

@ -173,5 +173,4 @@ object Env {
def coach = lila.coach.Env.current
def pool = lila.pool.Env.current
def practice = lila.practice.Env.current
def evalCache = lila.evalCache.Env.current
}

View File

@ -542,7 +542,7 @@ challenge {
uid.timeout = 7 seconds
max_playing = ${setup.max_playing}
}
eval_cache {
evalCache {
collection.eval_cache = eval_cache
}
study {

View File

@ -4,6 +4,8 @@ import scala.concurrent.duration._
import chess.format.{ FEN, Uci }
import lila.db.dsl._
import lila.socket.Handler.Controller
import lila.user.User
final class EvalCacheApi(coll: Coll) {
@ -14,6 +16,15 @@ final class EvalCacheApi(coll: Coll) {
def put(candidate: Input.Candidate): Funit = candidate.input ?? put
def socketHandler(user: Option[User]): Controller =
user.filter(canPut).fold(lila.socket.Handler.emptyController)(makeController)
private def canPut(user: User) = true
private def makeController(user: User): Controller = {
case ("evalPut", o) => EvalCacheParser.parsePut(user, o.pp).pp foreach put
}
private def getEval(id: Id): Fu[Option[Eval]] = getEntry(id) map {
_.flatMap(_.bestEval)
}

View File

@ -6,22 +6,12 @@ import play.api.libs.json.JsObject
import chess.format.Uci
import EvalCacheEntry._
import lila.common.PimpedJson._
import lila.socket.Handler.Controller
import lila.tree.Eval._
import lila.user.User
final class SocketHandler(api: EvalCacheApi) {
private object EvalCacheParser {
def controller(user: User): Controller =
if (canPut(user)) makeController(user)
else lila.socket.Handler.emptyController
private def makeController(user: User): Controller = {
case ("evalPut", o) => parsePut(user, o) foreach api.put
}
private def parsePut(user: User, o: JsObject): Option[Input.Candidate] = for {
def parsePut(user: User, o: JsObject): Option[Input.Candidate] = for {
d <- o obj "d"
variant = chess.variant.Variant orDefault ~d.str("variant")
if variant.standard
@ -40,7 +30,7 @@ final class SocketHandler(api: EvalCacheApi) {
date = DateTime.now))
private def parsePv(d: JsObject): Option[Pv] = for {
movesStr <- d str "pv"
movesStr <- d str "moves"
moves <- movesStr.split(' ').take(EvalCacheEntry.MAX_PV_SIZE).toList.foldLeft(List.empty[Uci].some) {
case (Some(ucis), str) => Uci(str) map (_ :: ucis)
case _ => None
@ -49,6 +39,4 @@ final class SocketHandler(api: EvalCacheApi) {
mate = d int "mate" map Mate.apply
score <- cp.map(Score.cp) orElse mate.map(Score.mate)
} yield Pv(score, moves)
private def canPut(user: User) = true
}

View File

@ -18,6 +18,7 @@ final class Env(
lightUserApi: lila.user.LightUserApi,
gamePgnDump: lila.game.PgnDump,
importer: lila.importer.Importer,
evalCache: lila.evalCache.EvalCacheApi,
system: ActorSystem,
hub: lila.hub.Env,
db: lila.db.Env) {
@ -57,7 +58,8 @@ final class Env(
socketHub = socketHub,
chat = hub.actor.chat,
destCache = destCache,
api = api)
api = api,
evalCache = evalCache)
lazy val studyRepo = new StudyRepo(coll = db(CollectionStudy))
lazy val chapterRepo = new ChapterRepo(coll = db(CollectionChapter))
@ -129,6 +131,7 @@ object Env {
lightUserApi = lila.user.Env.current.lightUserApi,
gamePgnDump = lila.game.Env.current.pgnDump,
importer = lila.importer.Env.current.importer,
evalCache = lila.evalCache.Env.current.api,
system = lila.common.PlayApp.system,
hub = lila.hub.Env.current,
db = lila.db.Env.current)

View File

@ -23,7 +23,8 @@ private[study] final class SocketHandler(
socketHub: ActorRef,
chat: ActorSelection,
destCache: LoadingCache[AnaDests.Ref, AnaDests],
api: StudyApi) {
api: StudyApi,
evalCache: lila.evalCache.EvalCacheApi) {
import Handler.AnaRateLimit
import JsonView.shapeReader
@ -40,7 +41,8 @@ private[study] final class SocketHandler(
studyId: Study.Id,
uid: Uid,
member: Socket.Member,
owner: Boolean): Handler.Controller = ({
owner: Boolean,
user: Option[User]): Handler.Controller = ({
case ("p", o) => o int "v" foreach { v =>
socket ! PingVersion(uid.value, v)
}
@ -233,7 +235,7 @@ private[study] final class SocketHandler(
byUserId <- member.userId
v <- (o \ "d" \ "liked").asOpt[Boolean]
} api.like(studyId, byUserId, v, socket, uid)
}: Handler.Controller) orElse lila.chat.Socket.in(
}: Handler.Controller) orElse evalCache.socketHandler(user) orElse lila.chat.Socket.in(
chatId = studyId.value,
member = member,
socket = socket,
@ -264,7 +266,7 @@ private[study] final class SocketHandler(
join = Socket.Join(uid = uid, userId = user.map(_.id), troll = user.??(_.troll), owner = owner)
handler Handler(hub, socket, uid.value, join) {
case Socket.Connected(enum, member) =>
(controller(socket, studyId, uid, member, owner = owner), enum, member)
(controller(socket, studyId, uid, member, owner = owner, user = user), enum, member)
}
} yield handler.some
}

View File

@ -240,7 +240,8 @@ object ApplicationBuild extends Build {
libraryDependencies ++= provided(play.api, reactivemongo.driver)
)
lazy val study = project("study", Seq(common, db, hub, socket, game, round, importer, notifyModule, relation)).settings(
lazy val study = project("study", Seq(
common, db, hub, socket, game, round, importer, notifyModule, relation, evalCache)).settings(
libraryDependencies ++= provided(play.api, reactivemongo.driver)
)

View File

@ -171,6 +171,7 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
// var evalPutMinNodes = 5e6;
var evalPutMinDepth = 16;
var evalPutMinNodes = 1e6;
var evalPutMaxMoves = 8;
var onCeval = throttle(1000, false, function(eval) {
if (isStandard() && eval.depth >= evalPutMinDepth && eval.nodes > evalPutMinNodes) send("evalPut", {
fen: eval.fen,
@ -181,7 +182,7 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
return {
cp: pv.cp,
mate: pv.mate,
moves: pv.pv
moves: pv.pv.split(' ').slice(0, evalPutMaxMoves).join(' ')
};
})
});