explicit reflective calls, upgrade scalalib and scalachess

pull/5750/head
Thibault Duplessis 2019-12-13 12:45:21 -06:00
parent f1d9188497
commit 089b807c03
13 changed files with 103 additions and 90 deletions

View File

@ -19,7 +19,7 @@ trait NumberHelper { self: I18nHelper =>
def showMillis(millis: Int)(implicit ctx: UserContext) = formatter.format((millis / 100).toDouble / 10)
implicit def richInt(number: Int) = new {
implicit final class RichInt(number: Int) {
def localize(implicit ctx: UserContext): String = formatter format number
}
}

View File

@ -5,32 +5,34 @@ import lila.common.paginator.Paginator
trait PaginatorHelper {
implicit def toRichPager[A](pager: Paginator[A]) = new {
def sliding(length: Int, showPost: Boolean = true): List[Option[Int]] = {
val fromPage = 1 max (pager.currentPage - length)
val toPage = pager.nbPages min (pager.currentPage + length)
val pre = fromPage match {
case 1 => Nil
case 2 => List(1.some)
case _ => List(1.some, none)
}
val post = toPage match {
case x if x == pager.nbPages => Nil
case x if x == pager.nbPages - 1 => List(pager.nbPages.some)
case _ if showPost => List(none, pager.nbPages.some)
case _ => List(none)
}
pre ::: (fromPage to toPage).view.map(some).toList ::: post
}
def firstIndex: Int =
(pager.maxPerPage.value * (pager.currentPage - 1) + 1) min pager.nbResults
def lastIndex: Int =
(firstIndex + pageNbResults - 1) max 0
def pageNbResults =
pager.currentPageResults.size
}
implicit def toRichPager[A](pager: Paginator[A]): RichPager = new RichPager(pager)
}
final class RichPager(pager: Paginator[_]) {
def sliding(length: Int, showPost: Boolean = true): List[Option[Int]] = {
val fromPage = 1 max (pager.currentPage - length)
val toPage = pager.nbPages min (pager.currentPage + length)
val pre = fromPage match {
case 1 => Nil
case 2 => List(1.some)
case _ => List(1.some, none)
}
val post = toPage match {
case x if x == pager.nbPages => Nil
case x if x == pager.nbPages - 1 => List(pager.nbPages.some)
case _ if showPost => List(none, pager.nbPages.some)
case _ => List(none)
}
pre ::: (fromPage to toPage).view.map(some).toList ::: post
}
def firstIndex: Int =
(pager.maxPerPage.value * (pager.currentPage - 1) + 1) min pager.nbResults
def lastIndex: Int =
(firstIndex + pageNbResults - 1) max 0
def pageNbResults =
pager.currentPageResults.size
}

View File

@ -16,11 +16,6 @@ trait StringHelper { self: NumberHelper =>
def urlencode(str: String): String = java.net.URLEncoder.encode(str, "US-ASCII")
implicit def lilaRichString(str: String) = new {
def active(other: String, one: String = "active") = if (str == other) one else ""
def activeO(other: String, one: String = "active") = if (str == other) Some(one) else None
}
def when(cond: Boolean, str: String) = cond ?? str
private val NumberFirstRegex = """(\d++)\s(.+)""".r
@ -58,4 +53,11 @@ trait StringHelper { self: NumberHelper =>
frag(separator, f)
}
}
implicit def lilaRichString(str: String): LilaRichString = new LilaRichString(str)
}
final class LilaRichString(val str: String) extends AnyVal {
def active(other: String, one: String = "active") = if (str == other) one else ""
def activeO(other: String, one: String = "active") = if (str == other) Some(one) else None
}

View File

@ -2,6 +2,7 @@ package views.html.base
import lila.common.String.html.safeJsonValue
import play.api.libs.json.Json
import scala.language.reflectiveCalls
import lila.api.Context
import lila.app.templating.Environment._

View File

@ -27,6 +27,7 @@ object Captcha {
val failMessage = "captcha.fail"
import scala.language.reflectiveCalls
def isFailed(form: Form.FormLike) =
form.errors.exists { _.messages has failMessage }
}

View File

@ -437,16 +437,17 @@ object mon {
}
object fishnet {
object client {
def result(client: String) = new {
private val c = counter("fishnet.client.result")
private def apply(r: String): Counter = c.withTags(Map("client" -> client, "result" -> r))
val success = apply("success")
val failure = apply("failure")
val weak = apply("weak")
val timeout = apply("timeout")
val notFound = apply("notFound")
val notAcquired = apply("notAcquired")
val abort = apply("abort")
object result {
private val c = counter("fishnet.client.result")
private def apply(r: String)(client: String): Counter =
c.withTags(Map("client" -> client, "result" -> r))
val success = apply("success") _
val failure = apply("failure") _
val weak = apply("weak") _
val timeout = apply("timeout") _
val notFound = apply("notFound") _
val notAcquired = apply("notAcquired") _
val abort = apply("abort") _
}
def status(enabled: Boolean) = gauge("fishnet.client.status").withTag("enabled", enabled)
def version(v: String) = gauge("fishnet.client.version").withTag("version", v)
@ -461,19 +462,21 @@ object mon {
val forUser = gauge("fishnet.work.forUser").withoutTags
}
object analysis {
def by(client: String) = new {
val hash = histogram("fishnet.analysis.hash").withTag("client", client)
val threads = gauge("fishnet.analysis.threads").withTag("client", client)
val movetime = histogram("fishnet.analysis.movetime").withTag("client", client)
val node = histogram("fishnet.analysis.node").withTag("client", client)
val nps = histogram("fishnet.analysis.nps").withTag("client", client)
val depth = histogram("fishnet.analysis.depth").withTag("client", client)
val pvSize = histogram("fishnet.analysis.pvSize").withTag("client", client)
def pv(isLong: Boolean) =
object by {
def hash(client: String) = histogram("fishnet.analysis.hash").withTag("client", client)
def threads(client: String) = gauge("fishnet.analysis.threads").withTag("client", client)
def movetime(client: String) = histogram("fishnet.analysis.movetime").withTag("client", client)
def node(client: String) = histogram("fishnet.analysis.node").withTag("client", client)
def nps(client: String) = histogram("fishnet.analysis.nps").withTag("client", client)
def depth(client: String) = histogram("fishnet.analysis.depth").withTag("client", client)
def pvSize(client: String) = histogram("fishnet.analysis.pvSize").withTag("client", client)
def pv(client: String, isLong: Boolean) =
counter("fishnet.analysis.pvs").withTags(Map("client" -> client, "long" -> isLong))
val totalMeganode = counter("fishnet.analysis.total.meganode").withTag("client", client)
val totalSecond = counter("fishnet.analysis.total.second").withTag("client", client)
val totalPosition = counter("fishnet.analysis.total.position").withTag("client", client)
def totalMeganode(client: String) =
counter("fishnet.analysis.total.meganode").withTag("client", client)
def totalSecond(client: String) = counter("fishnet.analysis.total.second").withTag("client", client)
def totalPosition(client: String) =
counter("fishnet.analysis.total.position").withTag("client", client)
}
val post = timer("fishnet.analysis.post").withoutTags
def requestCount(tpe: String) = counter("fishnet.analysis.request").withTag("type", tpe)

View File

@ -6,6 +6,8 @@ final private class Monitor(
repo: FishnetRepo
)(implicit system: akka.actor.ActorSystem) {
private val monBy = lila.mon.fishnet.analysis.by
private def sumOf[A](items: List[A])(f: A => Option[Int]) = items.foldLeft(0) {
case (acc, a) => acc + f(a).getOrElse(0)
}
@ -17,17 +19,19 @@ final private class Monitor(
) = {
Monitor.success(work, client)
val monitor = lila.mon.fishnet.analysis by client.userId.value
val threads = result.stockfish.options.threadsInt
val userId = client.userId.value
result.stockfish.options.hashInt foreach { monitor.hash.record(_) }
result.stockfish.options.threadsInt foreach { monitor.threads.update(_) }
result.stockfish.options.hashInt foreach { monBy.hash(userId).record(_) }
result.stockfish.options.threadsInt foreach { monBy.threads(userId).update(_) }
monitor.totalSecond.increment(sumOf(result.evaluations)(_.time) * threads.|(1) / 1000)
monitor.totalMeganode.increment(sumOf(result.evaluations) { eval =>
eval.nodes ifFalse eval.mateFound
} / 1000000)
monitor.totalPosition.increment(result.evaluations.size)
monBy.totalSecond(userId).increment(sumOf(result.evaluations)(_.time) * threads.|(1) / 1000)
monBy
.totalMeganode(userId)
.increment(sumOf(result.evaluations) { eval =>
eval.nodes ifFalse eval.mateFound
} / 1000000)
monBy.totalPosition(userId).increment(result.evaluations.size)
val metaMovesSample = sample(result.evaluations.drop(6).filterNot(_.mateFound), 100)
def avgOf(f: JsonApi.Request.Evaluation => Option[Int]): Option[Int] = {
@ -39,17 +43,17 @@ final private class Monitor(
}
(nb > 0) option (sum / nb)
}
avgOf(_.time) foreach { monitor.movetime.record(_) }
avgOf(_.nodes) foreach { monitor.node.record(_) }
avgOf(_.cappedNps) foreach { monitor.nps.record(_) }
avgOf(_.depth) foreach { monitor.depth.record(_) }
avgOf(_.pv.size.some) foreach { monitor.pvSize.record(_) }
avgOf(_.time) foreach { monBy.movetime(userId).record(_) }
avgOf(_.nodes) foreach { monBy.node(userId).record(_) }
avgOf(_.cappedNps) foreach { monBy.nps(userId).record(_) }
avgOf(_.depth) foreach { monBy.depth(userId).record(_) }
avgOf(_.pv.size.some) foreach { monBy.pvSize(userId).record(_) }
val significantPvSizes =
result.evaluations.filterNot(_.mateFound).filterNot(_.deadDraw).map(_.pv.size)
monitor.pv(false).increment(significantPvSizes.count(_ < 3))
monitor.pv(true).increment(significantPvSizes.count(_ >= 6))
monBy.pv(userId, false).increment(significantPvSizes.count(_ < 3))
monBy.pv(userId, true).increment(significantPvSizes.count(_ >= 6))
}
private def sample[A](elems: List[A], n: Int) =
@ -94,9 +98,11 @@ final private class Monitor(
object Monitor {
private val monResult = lila.mon.fishnet.client.result
private def success(work: Work, client: Client) = {
lila.mon.fishnet.client.result(client.userId.value).success.increment()
monResult.success(client.userId.value).increment()
work.acquiredAt foreach { acquiredAt =>
lila.mon.fishnet.queue.record {
@ -107,31 +113,31 @@ object Monitor {
private[fishnet] def failure(work: Work, client: Client, e: Exception) = {
logger.warn(s"Received invalid analysis ${work.id} for ${work.game.id} by ${client.fullId}", e)
lila.mon.fishnet.client.result(client.userId.value).failure.increment()
monResult.failure(client.userId.value).increment()
}
private[fishnet] def weak(work: Work, client: Client, data: JsonApi.Request.CompleteAnalysis) = {
logger.warn(
s"Received weak analysis ${work.id} (nodes: ${~data.medianNodes}) for ${work.game.id} by ${client.fullId}"
)
lila.mon.fishnet.client.result(client.userId.value).weak.increment()
monResult.weak(client.userId.value).increment()
}
private[fishnet] def timeout(userId: Client.UserId) =
lila.mon.fishnet.client.result(userId.value).timeout.increment()
monResult.timeout(userId.value).increment()
private[fishnet] def abort(client: Client) =
lila.mon.fishnet.client.result(client.userId.value).abort.increment()
monResult.abort(client.userId.value).increment()
private[fishnet] def notFound(id: Work.Id, client: Client) = {
logger.info(s"Received unknown analysis $id by ${client.fullId}")
lila.mon.fishnet.client.result(client.userId.value).notFound.increment()
monResult.notFound(client.userId.value).increment()
}
private[fishnet] def notAcquired(work: Work, client: Client) = {
logger.info(
s"Received unacquired analysis ${work.id} for ${work.game.id} by ${client.fullId}. Work current tries: ${work.tries} acquired: ${work.acquired}"
)
lila.mon.fishnet.client.result(client.userId.value).notAcquired.increment()
monResult.notAcquired(client.userId.value).increment()
}
}

View File

@ -6,7 +6,7 @@ import chess.{ Black, Clock, White }
import lila.common.Future
import lila.game.{ Game, GameRepo, UciMemo }
import ornicar.scalalib.Random.approximatly
import ornicar.scalalib.Random.approximately
final class Player(
redis: FishnetRedis,
@ -40,7 +40,7 @@ final class Player(
sleep = (delay * accel) atMost 500
if sleep > 25
millis = sleep * 10
randomized = approximatly(0.5f)(millis)
randomized = approximately(0.5f)(millis)
divided = randomized / (if (g.turns > 9) 1 else 2)
} yield divided.millis

View File

@ -219,7 +219,7 @@ object BSONHandlers {
}
}
implicit val lightGameBSONHandler = new lila.db.BSONReadOnly[LightGame] {
implicit object lightGameBSONHandler extends lila.db.BSONReadOnly[LightGame] {
import Game.{ BSONFields => F }
import Player.playerBSONHandler

View File

@ -95,7 +95,7 @@ object Crosstable {
val lastPlayed = "d"
}
implicit private[game] val crosstableBSONHandler = new BSON[Crosstable] {
implicit private[game] object crosstableBSONHandler extends BSON[Crosstable] {
import BSONFields._

View File

@ -26,6 +26,7 @@ trait CaptchedForm {
def withCaptcha[A](form: Form[A]): Fu[(Form[A], Captcha)] =
anyCaptcha map (form -> _)
import scala.language.reflectiveCalls
def validateCaptcha(data: CaptchedData) =
getCaptcha(data.gameId) awaitSeconds 2 valid data.move.trim.toLowerCase

View File

@ -51,7 +51,6 @@ object BuildSettings {
val compilerOptions = Seq(
"-language:implicitConversions",
"-language:postfixOps",
"-language:reflectiveCalls", // #TODO remove me for perfs
"-feature",
"-unchecked",
"-deprecation",

View File

@ -12,10 +12,10 @@ object Dependencies {
}
val scalaz = "org.scalaz" %% "scalaz-core" % "7.2.29"
val scalalib = "com.github.ornicar" %% "scalalib" % "6.7"
val scalalib = "com.github.ornicar" %% "scalalib" % "6.8"
val hasher = "com.roundeights" %% "hasher" % "1.2.1"
val jodaTime = "joda-time" % "joda-time" % "2.10.5"
val chess = "org.lichess" %% "scalachess" % "9.0.27"
val chess = "org.lichess" %% "scalachess" % "9.1.0"
val compression = "org.lichess" %% "compression" % "1.5"
val maxmind = "com.sanoma.cda" %% "maxmind-geoip2-scala" % "1.3.1-THIB"
val prismic = "io.prismic" %% "scala-kit" % "1.2.13-THIB213"
@ -40,11 +40,9 @@ object Dependencies {
val driver = "org.reactivemongo" %% "reactivemongo" % version
val bson = "org.reactivemongo" %% "reactivemongo-bson-api" % version
val stream = "org.reactivemongo" %% "reactivemongo-akkastream" % version
// val native = "org.reactivemongo" % "reactivemongo-shaded-native" % s"$version-linux-x86-64" classifier "linux-x86_64"
val native = "org.reactivemongo" % "reactivemongo-shaded-native" % s"$version-linux-x86-64"
// #TODO remove compat
val compat = "org.reactivemongo" %% "reactivemongo-bson-compat" % version
def bundle = Seq(driver, bson, compat, stream)
val native = "org.reactivemongo" % "reactivemongo-shaded-native" % s"$version-linux-x86-64"
val compat = "org.reactivemongo" %% "reactivemongo-bson-compat" % version
def bundle = Seq(driver, bson, compat, stream)
}
object play {