cache more game collection queries

pull/83/head
Thibault Duplessis 2013-09-18 02:40:25 +02:00
parent e1f32fa38b
commit 922571e8ec
7 changed files with 51 additions and 31 deletions

View File

@ -29,6 +29,7 @@ final class Env(
bookmarkApi = Env.bookmark.api, bookmarkApi = Env.bookmark.api,
eloCalculator = Env.round.eloCalculator, eloCalculator = Env.round.eloCalculator,
relationApi = Env.relation.api, relationApi = Env.relation.api,
gameCached = Env.game.cached,
postApi = Env.forum.postApi, postApi = Env.forum.postApi,
getRank = Env.user.ranking.get) _ getRank = Env.user.ranking.get) _

View File

@ -36,7 +36,7 @@ object Tv extends LilaController {
private def confrontation(game: GameModel): Fu[Option[Confrontation]] = ~{ private def confrontation(game: GameModel): Fu[Option[Confrontation]] = ~{
(game.creator.userId |@| game.invited.userId) apply { (game.creator.userId |@| game.invited.userId) apply {
case (id1, id2) (UserRepo byId id1) zip (UserRepo byId id2) flatMap { case (id1, id2) (UserRepo byId id1) zip (UserRepo byId id2) flatMap {
case (Some(user1), Some(user2)) GameRepo.confrontation(user1, user2) map (_.some) case (Some(user1), Some(user2)) Env.game.cached.confrontation(user1, user2) map (_.some)
case _ fuccess(none) case _ fuccess(none)
} }
} }

View File

@ -36,16 +36,17 @@ object UserInfo {
bookmarkApi: BookmarkApi, bookmarkApi: BookmarkApi,
eloCalculator: EloCalculator, eloCalculator: EloCalculator,
relationApi: RelationApi, relationApi: RelationApi,
gameCached: lila.game.Cached,
postApi: PostApi, postApi: PostApi,
getRank: String Fu[Option[Int]])(user: User, ctx: Context): Fu[UserInfo] = getRank: String Fu[Option[Int]])(user: User, ctx: Context): Fu[UserInfo] =
(getRank(user.id) flatMap { (getRank(user.id) flatMap {
_ ?? { rank countUsers() map { nb (rank -> nb).some } } _ ?? { rank countUsers() map { nb (rank -> nb).some } }
}) zip }) zip
((ctx is user) ?? { ((ctx is user) ?? {
GameRepo count (_ notFinished user.id) map (_.some) gameCached nbPlaying user.id map (_.some)
}) zip }) zip
(ctx.me.filter(user!=) ?? { me (ctx.me.filter(user!=) ?? { me
GameRepo.confrontation(me, user) map (_.some filterNot (_.empty)) gameCached.confrontation(me, user) map (_.some filterNot (_.empty))
}) zip }) zip
(bookmarkApi countByUser user) zip (bookmarkApi countByUser user) zip
EloChart(user) zip EloChart(user) zip

View File

@ -1,7 +1,7 @@
@(c: lila.user.Confrontation)(implicit ctx: Context) @(c: lila.user.Confrontation)(implicit ctx: Context)
<div class="confrontation boxed_data"> <div class="confrontation boxed_data">
<div class="vs">@userLink(c.user1, withElo = false, withOnline = false) vs @userLink(c.user2, withElo = false, withOnline = false)</div> <div class="vs">@userIdLink(c.user1.some, withOnline = false) vs @userIdLink(c.user2.some, withOnline = false)</div>
@trans.nbWins("<strong>"+c.wins+"</strong>"), @trans.nbWins("<strong>"+c.wins+"</strong>"),
@trans.nbDraws("<strong>"+c.draws+"</strong>"), @trans.nbDraws("<strong>"+c.draws+"</strong>"),
@trans.nbLosses("<strong>"+c.losses+"</strong>") @trans.nbLosses("<strong>"+c.losses+"</strong>")

View File

@ -9,15 +9,23 @@ import lila.memo.AsyncCache
import lila.user.{ User, Confrontation } import lila.user.{ User, Confrontation }
import tube.gameTube import tube.gameTube
private[game] final class Cached(ttl: Duration) { final class Cached(ttl: Duration) {
def nbGames: Fu[Int] = count(Query.all) def nbGames: Fu[Int] = count(Query.all)
def nbMates: Fu[Int] = count(Query.mate) def nbMates: Fu[Int] = count(Query.mate)
def nbPopular: Fu[Int] = count(Query.popular) def nbPopular: Fu[Int] = count(Query.popular)
def nbImported: Fu[Int] = count(Query.imported) def nbImported: Fu[Int] = count(Query.imported)
def confrontation(user1: User, user2: User): Fu[Confrontation] = def nbPlaying(userId: String): Fu[Int] = count(Query notFinished userId)
confrontationCache(List(user1, user2).sortBy(_.count.game).map(_.id))
def confrontation(user1: User, user2: User): Fu[Confrontation] = {
def idGame(user: User) = (user.id, user.count.game)
confrontationCache {
(user1 < user2).fold(
idGame(user1) -> idGame(user2),
idGame(user2) -> idGame(user1))
}
}
private val confrontationCache = private val confrontationCache =
AsyncCache(GameRepo.confrontation, timeToLive = 1.minute) AsyncCache(GameRepo.confrontation, timeToLive = 1.minute)

View File

@ -226,32 +226,37 @@ object GameRepo {
_ sort Query.sortCreated skip (Random nextInt 1000) _ sort Query.sortCreated skip (Random nextInt 1000)
) )
// user1 wins, draws, losses // gets 2 users (id, nbGames)
// returns user1 wins, draws, losses
// the 2 userIds SHOULD be sorted by game count desc // the 2 userIds SHOULD be sorted by game count desc
// this method is cached in lila.game.Cached // this method is cached in lila.game.Cached
private[game] def confrontation(userIds: List[String]): Fu[Confrontation] = { private[game] def confrontation(users: ((String, Int), (String, Int))): Fu[Confrontation] = users match {
import reactivemongo.bson._ case (user1, user2) {
import reactivemongo.core.commands._ import reactivemongo.bson._
val command = Aggregate(gameTube.coll.name, Seq( import reactivemongo.core.commands._
Match(BSONDocument( val userIds = List(user1, user2).sortBy(_._2).map(_._1)
"uids" -> BSONDocument("$all" -> userIds), val command = Aggregate(gameTube.coll.name, Seq(
"s" -> BSONDocument("$gte" -> chess.Status.Mate.id) Match(BSONDocument(
)), "uids" -> BSONDocument("$all" -> userIds),
GroupField("wid")("nb" -> SumValue(1)) "s" -> BSONDocument("$gte" -> chess.Status.Mate.id)
)) )),
gameTube.coll.db.command(command) map { stream GroupField("wid")("nb" -> SumValue(1))
val res = (stream.toList map { obj ))
toJSON(obj).asOpt[JsObject] flatMap { o gameTube.coll.db.command(command) map { stream
o int "nb" map { nb val res = (stream.toList map { obj
~(o str "_id") -> nb toJSON(obj).asOpt[JsObject] flatMap { o
o int "nb" map { nb
~(o str "_id") -> nb
}
} }
} }).flatten.toMap
}).flatten.toMap Confrontation(
Confrontation( user1._1, user2._1,
~(res get ~userIds.lift(0)), ~(res get user1._1),
~(res get ""), ~(res get ""),
~(res get ~userIds.lift(1)) ~(res get user2._1)
) )
}
} }
} }
} }

View File

@ -1,6 +1,11 @@
package lila.user package lila.user
case class Confrontation(wins: Int, draws: Int, losses: Int) { case class Confrontation(
user1: String,
user2: String,
wins: Int,
draws: Int,
losses: Int) {
def games = wins + draws + losses def games = wins + draws + losses