make leaderboard caches easier on memory

This commit is contained in:
Thibault Duplessis 2016-01-11 09:07:45 +07:00
parent 4ff0ea41a0
commit 890f5b5195
6 changed files with 49 additions and 49 deletions

View file

@ -139,11 +139,11 @@ object User extends LilaController {
antichess <- env.cached top10Perf PerfType.Antichess.key antichess <- env.cached top10Perf PerfType.Antichess.key
atomic <- env.cached top10Perf PerfType.Atomic.key atomic <- env.cached top10Perf PerfType.Atomic.key
horde <- env.cached top10Perf PerfType.Horde.key horde <- env.cached top10Perf PerfType.Horde.key
nbAllTime env.cached topNbGame nb map2 { (user: UserModel) => nbAllTime env.cached topNbGame nb
user -> user.count.game nbDay Env.game.cached activePlayerUidsDay nb map {
} _ flatMap { pair =>
nbDay Env.game.cached activePlayerUidsDay nb flatMap { pairs => env lightUser pair.userId map { UserModel.LightCount(_, pair.nb) }
UserRepo.byOrderedIds(pairs.map(_.userId)) map (_ zip pairs.map(_.nb)) }
} }
tourneyWinners Env.tournament.winners scheduled nb tourneyWinners Env.tournament.winners scheduled nb
online env.cached topOnline 50 online env.cached topOnline 50
@ -163,9 +163,15 @@ object User extends LilaController {
nbDay = nbDay, nbDay = nbDay,
nbAllTime = nbAllTime))), nbAllTime = nbAllTime))),
api = _ => fuccess { api = _ => fuccess {
implicit val userWrites = play.api.libs.json.Writes[UserModel] { env.jsonView(_, true) } implicit val lightPerfWrites = play.api.libs.json.Writes[UserModel.LightPerf] { l =>
Json.obj(
"id" -> l.user.id,
"username" -> l.user.name,
"title" -> l.user.title,
"perfs" -> Json.obj(
l.perfKey -> Json.obj("rating" -> l.rating, "progress" -> l.progress)))
}
Ok(Json.obj( Ok(Json.obj(
"online" -> online,
"bullet" -> bullet, "bullet" -> bullet,
"blitz" -> blitz, "blitz" -> blitz,
"classical" -> classical, "classical" -> classical,

View file

@ -16,7 +16,7 @@ import play.api.libs.json._
final class Preload( final class Preload(
tv: Tv, tv: Tv,
leaderboard: Boolean => Fu[List[(User, PerfType)]], leaderboard: Boolean => Fu[List[User.LightPerf]],
tourneyWinners: Int => Fu[List[Winner]], tourneyWinners: Int => Fu[List[Winner]],
timelineEntries: String => Fu[List[Entry]], timelineEntries: String => Fu[List[Entry]],
streamsOnAir: () => Fu[List[StreamOnAir]], streamsOnAir: () => Fu[List[StreamOnAir]],
@ -26,7 +26,7 @@ final class Preload(
getPlayban: String => Fu[Option[TempBan]], getPlayban: String => Fu[Option[TempBan]],
lightUser: String => Option[LightUser]) { lightUser: String => Option[LightUser]) {
private type Response = (JsObject, List[Entry], List[MiniForumPost], List[Tournament], List[Simul], Option[Game], List[(User, PerfType)], List[Winner], Option[lila.puzzle.DailyPuzzle], List[StreamOnAir], List[lila.blog.MiniPost], Option[TempBan], Option[Preload.CurrentGame], Int) private type Response = (JsObject, List[Entry], List[MiniForumPost], List[Tournament], List[Simul], Option[Game], List[User.LightPerf], List[Winner], Option[lila.puzzle.DailyPuzzle], List[StreamOnAir], List[lila.blog.MiniPost], Option[TempBan], Option[Preload.CurrentGame], Int)
def apply( def apply(
posts: Fu[List[MiniForumPost]], posts: Fu[List[MiniForumPost]],

View file

@ -1,4 +1,4 @@
@(data: play.api.libs.json.JsObject, userTimeline: List[lila.timeline.Entry], forumRecent: List[lila.forum.MiniForumPost], tours: List[Tournament], simuls: List[lila.simul.Simul], featured: Option[Game], leaderboard: List[(User, lila.rating.PerfType)], tournamentWinners: List[lila.tournament.Winner], puzzle: Option[lila.puzzle.DailyPuzzle], streams: List[lila.tv.StreamOnAir], lastPost: List[lila.blog.MiniPost], playban: Option[lila.playban.TempBan], currentGame: Option[lila.app.mashup.Preload.CurrentGame], nbRounds: Int)(implicit ctx: Context) @(data: play.api.libs.json.JsObject, userTimeline: List[lila.timeline.Entry], forumRecent: List[lila.forum.MiniForumPost], tours: List[Tournament], simuls: List[lila.simul.Simul], featured: Option[Game], leaderboard: List[User.LightPerf], tournamentWinners: List[lila.tournament.Winner], puzzle: Option[lila.puzzle.DailyPuzzle], streams: List[lila.tv.StreamOnAir], lastPost: List[lila.blog.MiniPost], playban: Option[lila.playban.TempBan], currentGame: Option[lila.app.mashup.Preload.CurrentGame], nbRounds: Int)(implicit ctx: Context)
@underchat = { @underchat = {
<div id="featured_game"> <div id="featured_game">
@ -140,15 +140,15 @@ description = trans.freeOnlineChessGamePlayChessNowInACleanInterfaceNoRegistrati
<div class="undertable_inner scroll-shadow-hard"> <div class="undertable_inner scroll-shadow-hard">
<table> <table>
<tbody> <tbody>
@leaderboard.map { @leaderboard.map { l =>
case (u, pt) => {
<tr> <tr>
<td>@userLink(u)</td> <td>@lightUserLink(l.user)</td>
<td>@showPerfRating(u, pt, klass = "title")</td> @lila.rating.PerfType(l.perfKey).map { pt =>
<td>@showProgress(u.perfs(pt).progress, withTitle = false)</td> <td data-icon="@pt.iconChar">l.rating</td>
}
<td>@showProgress(l.progress, withTitle = false)</td>
</tr> </tr>
} }
}
</tbody> </tbody>
</table> </table>
</div> </div>

View file

@ -1,20 +1,18 @@
@(tourneyWinners: List[lila.tournament.Winner], online: List[User], bullet: List[User], blitz: List[User], classical: List[User], chess960: List[User], kingOfTheHill: List[User], threeCheck: List[User], antichess: List[User], atomic: List[User], horde: List[User], nbDay: List[(User, Int)], nbAllTime: List[(User, Int)])(implicit ctx: Context) @(tourneyWinners: List[lila.tournament.Winner], online: List[User], bullet: List[User.LightPerf], blitz: List[User.LightPerf], classical: List[User.LightPerf], chess960: List[User.LightPerf], kingOfTheHill: List[User.LightPerf], threeCheck: List[User.LightPerf], antichess: List[User.LightPerf], atomic: List[User.LightPerf], horde: List[User.LightPerf], nbDay: List[User.LightCount], nbAllTime: List[User.LightCount])(implicit ctx: Context)
@import lila.rating.PerfType @import lila.rating.PerfType
@userTopPerf(users: List[User], perfType: PerfType) = { @userTopPerf(users: List[User.LightPerf], perfType: PerfType) = {
<div class="user_top"> <div class="user_top">
<h2 class="text" data-icon="@perfType.iconChar"> <h2 class="text" data-icon="@perfType.iconChar">
<a href="@routes.User.top200(perfType.key)"> <a href="@routes.User.top200(perfType.key)">@perfType.name</a>
@perfType.name
</a>
</h2> </h2>
<table> <table>
<tbody> <tbody>
@users.map { u => @users.map { l =>
<tr> <tr>
<td>@userLink(u)</td> <td>@lightUserLink(l.user)</td>
<td>@u.perfs(perfType.key).map(_.intRating)</td> <td>@l.rating</td>
</tr> </tr>
} }
</tbody> </tbody>
@ -22,15 +20,15 @@
</div> </div>
} }
@userTopActive(users: List[(User, Int)], title: Any, icon: Option[Char] = None) = { @userTopActive(users: List[User.LightCount], title: Any, icon: Option[Char] = None) = {
<div class="user_top"> <div class="user_top">
<h2 class="text"@icon.map { i => data-icon="@i" }>@title</h2> <h2 class="text"@icon.map { i => data-icon="@i" }>@title</h2>
<table> <table>
<tbody> <tbody>
@users.map { u => @users.map { u =>
<tr> <tr>
<td>@userLink(u._1)</td> <td>@lightUserLink(u.user)</td>
<td title="@trans.gamesPlayed()">#@u._2.localize</td> <td title="@trans.gamesPlayed()">#@u.count.localize</td>
</tr> </tr>
} }
</tbody> </tbody>

View file

@ -12,8 +12,8 @@ import lila.db.BSON._
import lila.db.Implicits._ import lila.db.Implicits._
import lila.memo.{ ExpireSetMemo, MongoCache } import lila.memo.{ ExpireSetMemo, MongoCache }
import lila.rating.{ Perf, PerfType } import lila.rating.{ Perf, PerfType }
import User.LightPerf
import tube.userTube import tube.userTube
import User.{ LightPerf, LightCount }
final class Cached( final class Cached(
nbTtl: FiniteDuration, nbTtl: FiniteDuration,
@ -30,13 +30,15 @@ final class Cached(
def countEnabled: Fu[Int] = countCache(true) def countEnabled: Fu[Int] = countCache(true)
private implicit val userHandler = User.userBSONHandler
private implicit val LightUserBSONHandler = reactivemongo.bson.Macros.handler[LightUser] private implicit val LightUserBSONHandler = reactivemongo.bson.Macros.handler[LightUser]
private implicit val LightPerfBSONHandler = reactivemongo.bson.Macros.handler[LightPerf] private implicit val LightPerfBSONHandler = reactivemongo.bson.Macros.handler[LightPerf]
private implicit val LightCountBSONHandler = reactivemongo.bson.Macros.handler[LightCount]
val top10Perf = mongoCache[Perf.Key, List[User]]( val top10Perf = mongoCache[Perf.Key, List[LightPerf]](
prefix = "user:top10:perf", prefix = "user:top10:perf",
f = (perf: Perf.Key) => UserRepo.topPerfSince(perf, oneWeekAgo, 10), f = (perf: Perf.Key) => UserRepo.topPerfSince(perf, oneWeekAgo, 10) map {
_ flatMap (_ lightPerf perf)
},
timeToLive = 10 minutes) timeToLive = 10 minutes)
val top200Perf = mongoCache[Perf.Key, List[User.LightPerf]]( val top200Perf = mongoCache[Perf.Key, List[User.LightPerf]](
@ -46,26 +48,20 @@ final class Cached(
}, },
timeToLive = 10 minutes) timeToLive = 10 minutes)
private case class UserPerf(user: User, perfKey: String) private val topTodayCache = mongoCache.single[List[User.LightPerf]](
private implicit val UserPerfBSONHandler = reactivemongo.bson.Macros.handler[UserPerf]
private val topTodayCache = mongoCache.single[List[UserPerf]](
prefix = "user:top:today", prefix = "user:top:today",
f = PerfType.leaderboardable.map { perf => f = PerfType.leaderboardable.map { perf =>
UserRepo.topPerfSince(perf.key, DateTime.now minusHours 12, 1) map2 { (u: User) => UserRepo.topPerfSince(perf.key, DateTime.now minusHours 12, 1).map {
UserPerf(u, perf.key) _.headOption flatMap (_ lightPerf perf.key)
} }
}.sequenceFu map (_.flatten), }.sequenceFu.map(_.flatten),
timeToLive = 9 minutes) timeToLive = 9 minutes)
def topToday(x: Boolean): Fu[List[(User, PerfType)]] = def topToday = topTodayCache.apply _
topTodayCache(x) map2 { (up: UserPerf) =>
(up.user, PerfType(up.perfKey) err s"No such perf ${up.perfKey}")
}
val topNbGame = mongoCache[Int, List[User]]( val topNbGame = mongoCache[Int, List[User.LightCount]](
prefix = "user:top:nbGame", prefix = "user:top:nbGame",
f = UserRepo.topNbGame, f = nb => UserRepo topNbGame nb map { _ map (_.lightCount) },
timeToLive = 34 minutes) timeToLive = 34 minutes)
val topOnline = lila.memo.AsyncCache[Int, List[User]]( val topOnline = lila.memo.AsyncCache[Int, List[User]](

View file

@ -72,8 +72,10 @@ case class User(
def lameOrTroll = lame || troll def lameOrTroll = lame || troll
def lightPerf(key: String) = perfs(key) map { perf => def lightPerf(key: String) = perfs(key) map { perf =>
User.LightPerf(light, perf.intRating, perf.progress) User.LightPerf(light, key, perf.intRating, perf.progress)
} }
def lightCount = User.LightCount(light, count.game)
} }
object User { object User {
@ -82,10 +84,8 @@ object User {
val anonymous = "Anonymous" val anonymous = "Anonymous"
case class LightPerf( case class LightPerf(user: LightUser, perfKey: String, rating: Int, progress: Int)
user: LightUser, case class LightCount(user: LightUser, count: Int)
rating: Int,
progress: Int)
case class Active(user: User) case class Active(user: User)