smaller caches initial capacity in dev mode

pull/5819/head
Thibault Duplessis 2019-12-24 09:31:19 -05:00
parent 7be8cff864
commit b037980e15
27 changed files with 71 additions and 95 deletions

View File

@ -389,9 +389,8 @@ final class Tournament(
}
}
private val streamerCache = env.memo.cacheApi[Tour.ID, Set[UserModel.ID]]("tournament.streamers") {
_.initialCapacity(64)
.refreshAfterWrite(15.seconds)
private val streamerCache = env.memo.cacheApi[Tour.ID, Set[UserModel.ID]](64, "tournament.streamers") {
_.refreshAfterWrite(15.seconds)
.maximumSize(64)
.buildAsyncFuture { tourId =>
env.tournament.tournamentRepo.isUnfinished(tourId) flatMap {

View File

@ -43,9 +43,8 @@ final class ChallengeApi(
def onlineByIdFor(id: Challenge.ID, dest: User) = repo.byIdFor(id, dest).dmap(_.filter(_.online))
val countInFor = cacheApi[User.ID, Int]("challenge.countInFor") {
_.initialCapacity(65536)
.expireAfterAccess(20 minutes)
val countInFor = cacheApi[User.ID, Int](65536, "challenge.countInFor") {
_.expireAfterAccess(20 minutes)
.buildAsyncFuture(repo.countCreatedByDestId)
}

View File

@ -30,9 +30,8 @@ final class ChatApi(
// only use for public, multi-user chats - tournaments, simuls
object cached {
private val cache = cacheApi[Chat.Id, UserChat]("chat.user") {
_.initialCapacity(128)
.expireAfterAccess(1 minute)
private val cache = cacheApi[Chat.Id, UserChat](128, "chat.user") {
_.expireAfterAccess(1 minute)
.buildAsyncFuture(find)
}

View File

@ -47,9 +47,8 @@ final class EvalCacheApi(
coll.delete.one($id(id)).void >>- cache.invalidate(id)
}
private val cache = cacheApi[Id, Option[EvalCacheEntry]]("evalCache") {
_.initialCapacity(65536)
.expireAfterAccess(5 minutes)
private val cache = cacheApi[Id, Option[EvalCacheEntry]](65536, "evalCache") {
_.expireAfterAccess(5 minutes)
.buildAsyncFuture(fetchAndSetAccess)
}

View File

@ -27,9 +27,8 @@ final private class EvalCacheTruster(
nbGamesBonus(user)
}
private val userIdCache = cacheApi[User.ID, Option[TrustedUser]]("evalCache.userIdTrustCache") {
_.initialCapacity(256)
.expireAfterWrite(10 minutes)
private val userIdCache = cacheApi[User.ID, Option[TrustedUser]](256, "evalCache.userIdTrustCache") {
_.expireAfterWrite(10 minutes)
.buildAsyncFuture { userId =>
userRepo named userId map2 makeTrusted
}

View File

@ -15,9 +15,8 @@ final private class FishnetRepo(
import BSONHandlers._
private val clientCache = cacheApi[Client.Key, Option[Client]]("fishnet.client") {
_.initialCapacity(32)
.expireAfterWrite(10 minutes)
private val clientCache = cacheApi[Client.Key, Option[Client]](32, "fishnet.client") {
_.expireAfterWrite(10 minutes)
.buildAsyncFuture { key =>
clientColl.one[Client](selectClient(key))
}

View File

@ -35,9 +35,8 @@ final class Recent(
} mkString ";"
}
private val cache = cacheApi[String, List[MiniForumPost]]("forum.recent") {
_.initialCapacity(2048)
.expireAfterAccess(1 hour)
private val cache = cacheApi[String, List[MiniForumPost]](2048, "forum.recent") {
_.expireAfterAccess(1 hour)
.buildAsyncFuture(fetch)
}

View File

@ -19,9 +19,8 @@ final class Cached(
def nbPlaying = nbPlayingCache.get _
private val nbPlayingCache = cacheApi[User.ID, Int]("game.nbPlaying") {
_.initialCapacity(256)
.expireAfterAccess(15 seconds)
private val nbPlayingCache = cacheApi[User.ID, Int](256, "game.nbPlaying") {
_.expireAfterAccess(15 seconds)
.buildAsyncFuture { userId =>
gameRepo.coll.countSel(Query nowPlaying userId)
}

View File

@ -26,7 +26,7 @@ final class PlayTimeApi(
creationCache.get(user.id).withTimeoutDefault(1 second, none)
// to avoid creating it twice
private val creationCache = cacheApi[User.ID, Option[User.PlayTime]]("playTime") {
private val creationCache = cacheApi[User.ID, Option[User.PlayTime]](64, "playTime") {
_.expireAfterWrite(5 minutes)
.buildAsyncFuture(computeNow)
}

View File

@ -26,9 +26,8 @@ final class SeekApi(
.sort($sort desc "createdAt")
.cursor[Seek]()
private val cache = cacheApi[CacheKey, List[Seek]]("lobby.seek.list") {
_.initialCapacity(2)
.refreshAfterWrite(3 seconds)
private val cache = cacheApi[CacheKey, List[Seek]](2, "lobby.seek.list") {
_.refreshAfterWrite(3 seconds)
.buildAsyncFuture {
case ForAnon => allCursor.list(maxPerPage.value)
case ForUser => allCursor.list()

View File

@ -3,23 +3,29 @@ package lila.memo
import akka.actor.ActorSystem
import com.github.benmanes.caffeine
import com.github.blemale.scaffeine._
import play.api.Mode
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext
final class CacheApi(implicit ec: ExecutionContext, system: ActorSystem) {
final class CacheApi(mode: Mode)(implicit ec: ExecutionContext, system: ActorSystem) {
private type Builder = Scaffeine[Any, Any]
def scaffeine: Builder = Scaffeine().scheduler(caffeine.cache.Scheduler.systemScheduler)
def apply[K, V](name: String)(build: Builder => AsyncLoadingCache[K, V]): AsyncLoadingCache[K, V] = {
val cache = build(scaffeine)
def apply[K, V](initialCapacity: Int, name: String)(
build: Builder => AsyncLoadingCache[K, V]
): AsyncLoadingCache[K, V] = {
val actualCapacity =
if (mode != Mode.Prod) math.sqrt(initialCapacity).toInt atLeast 1
else initialCapacity
val cache = build(scaffeine initialCapacity actualCapacity)
monitor(name, cache)
cache
}
def unit[V](build: Builder => AsyncLoadingCache[Unit, V]): AsyncLoadingCache[Unit, V] = {
build(scaffeine.initialCapacity(1))
build(scaffeine initialCapacity 1)
}
def monitor(name: String, cache: AsyncCache[_, _]): Unit =

View File

@ -14,6 +14,7 @@ final class MemoConfig(
@Module
final class Env(
appConfig: Configuration,
mode: play.api.Mode,
db: lila.db.Db
)(implicit ec: scala.concurrent.ExecutionContext, system: akka.actor.ActorSystem) {

View File

@ -44,9 +44,8 @@ final class NotifyApi(
unreadCountCache.put(_, fuccess(0))
}
private val unreadCountCache = cacheApi[Notification.Notifies, Int]("notify.unreadCountCache") {
_.initialCapacity(32768)
.expireAfterAccess(20 minutes)
private val unreadCountCache = cacheApi[Notification.Notifies, Int](32768, "notify.unreadCountCache") {
_.expireAfterAccess(20 minutes)
.buildAsyncFuture(repo.unreadNotificationsCount)
}

View File

@ -49,9 +49,8 @@ final class OAuthServer(
}
private val accessTokenCache =
cacheApi[AccessToken.Id, Option[AccessToken.ForAuth]]("oauth.server.personal_access_token") {
_.initialCapacity(16)
.expireAfterWrite(5 minutes)
cacheApi[AccessToken.Id, Option[AccessToken.ForAuth]](16, "oauth.server.personal_access_token") {
_.expireAfterWrite(5 minutes)
.buildAsyncFuture(fetchAccessToken)
}

View File

@ -191,9 +191,8 @@ final class PlaybanApi(
def getRageSit(userId: User.ID) = rageSitCache get userId
private val rageSitCache = cacheApi[User.ID, RageSit]("playban.ragesit") {
private val rageSitCache = cacheApi[User.ID, RageSit](32768, "playban.ragesit") {
_.expireAfterAccess(20 minutes)
.initialCapacity(32768)
.buildAsyncFuture { userId =>
coll.primitiveOne[RageSit]($doc("_id" -> userId, "c" $exists true), "c").map(_ | RageSit.empty)
}

View File

@ -17,9 +17,8 @@ final class PrefApi(
private def fetchPref(id: User.ID): Fu[Option[Pref]] = coll.ext.find($id(id)).one[Pref]
private val cache = cacheApi[User.ID, Option[Pref]]("pref.fetchPref") {
_.initialCapacity(65536)
.expireAfterAccess(10 minutes)
private val cache = cacheApi[User.ID, Option[Pref]](65536, "pref.fetchPref") {
_.expireAfterAccess(10 minutes)
.buildAsyncFuture(fetchPref)
}

View File

@ -20,9 +20,8 @@ final private class GameJson(
private case class CacheKey(gameId: Game.ID, plies: Int, onlyLast: Boolean)
private val cache = cacheApi[CacheKey, JsObject]("puzzle.gameJson") {
_.initialCapacity(1024)
.expireAfterAccess(5 minutes)
private val cache = cacheApi[CacheKey, JsObject](1024, "puzzle.gameJson") {
_.expireAfterAccess(5 minutes)
.maximumSize(1024)
.buildAsyncFuture(generate)
}

View File

@ -73,9 +73,8 @@ final class RelationApi(
def fetchAreFriends(u1: ID, u2: ID): Fu[Boolean] =
fetchFollows(u1, u2) >>& fetchFollows(u2, u1)
private val countFollowingCache = cacheApi[ID, Int]("relation.count.following") {
_.initialCapacity(65536)
.expireAfterAccess(10 minutes)
private val countFollowingCache = cacheApi[ID, Int](65536, "relation.count.following") {
_.expireAfterAccess(10 minutes)
.maximumSize(65536)
.buildAsyncFuture { userId =>
coll.countSel($doc("u1" -> userId, "r" -> Follow))
@ -86,9 +85,8 @@ final class RelationApi(
def reachedMaxFollowing(userId: ID): Fu[Boolean] = countFollowingCache get userId map (config.maxFollow <=)
private val countFollowersCache = cacheApi[ID, Int]("relation.count.followers") {
_.initialCapacity(65536)
.expireAfterAccess(10 minutes)
private val countFollowersCache = cacheApi[ID, Int](65536, "relation.count.followers") {
_.expireAfterAccess(10 minutes)
.maximumSize(65536)
.buildAsyncFuture { userId =>
coll.countSel($doc("u2" -> userId, "r" -> Follow))

View File

@ -353,9 +353,8 @@ final class ReportApi(
object accuracy {
private val cache =
cacheApi[User.ID, Option[Accuracy]]("report.accuracy") {
cacheApi[User.ID, Option[Accuracy]](512, "report.accuracy") {
_.expireAfterWrite(24 hours)
.initialCapacity(512)
.buildAsyncFuture { reporterId =>
coll.ext
.find(

View File

@ -22,9 +22,8 @@ final class IpIntel(
else if (contactEmail.value.isEmpty) fuccess(0)
else cache get ip
private val cache = cacheApi[IpAddress, Int]("ipIntel") {
_.initialCapacity(8192)
.expireAfterWrite(3 days)
private val cache = cacheApi[IpAddress, Int](8192, "ipIntel") {
_.expireAfterWrite(3 days)
.buildAsyncFuture { ip =>
val url = s"https://check.getipintel.net/check.php?ip=$ip&contact=${contactEmail.value}"
ws.url(url)

View File

@ -75,9 +75,8 @@ final class Env(
lazy val pgnDump = wire[PgnDump]
lazy val lightStudyCache: LightStudyCache =
cacheApi[Study.Id, Option[Study.LightStudy]]("study.lightStudyCache") {
_.initialCapacity(512)
.expireAfterWrite(20 minutes)
cacheApi[Study.Id, Option[Study.LightStudy]](512, "study.lightStudyCache") {
_.expireAfterWrite(20 minutes)
.buildAsyncFuture(studyRepo.lightById)
}

View File

@ -42,9 +42,8 @@ final class Cached(
def invalidateTeamIds = teamIdsCache invalidate _
val nbRequests = cacheApi[User.ID, Int]("team.nbRequests") {
val nbRequests = cacheApi[User.ID, Int](32768, "team.nbRequests") {
_.expireAfterAccess(25 minutes)
.initialCapacity(32768)
.maximumSize(65536)
.buildAsyncFuture[User.ID, Int] { userId =>
teamRepo teamIdsByCreator userId flatMap requestRepo.countByTeams,

View File

@ -35,16 +35,14 @@ final private[tournament] class Cached(
else ongoingRanking get tour.id
// only applies to ongoing tournaments
private val ongoingRanking = cacheApi[Tournament.ID, Ranking]("tournament.ongoingRanking") {
_.initialCapacity(64)
.expireAfterWrite(3 seconds)
private val ongoingRanking = cacheApi[Tournament.ID, Ranking](64, "tournament.ongoingRanking") {
_.expireAfterWrite(3 seconds)
.buildAsyncFuture(playerRepo.computeRanking)
}
// only applies to finished tournaments
private val finishedRanking = cacheApi[Tournament.ID, Ranking]("tournament.finishedRanking") {
_.initialCapacity(1024)
.expireAfterAccess(1 hour)
private val finishedRanking = cacheApi[Tournament.ID, Ranking](1024, "tournament.finishedRanking") {
_.expireAfterAccess(1 hour)
.maximumSize(2048)
.buildAsyncFuture(playerRepo.computeRanking)
}
@ -69,9 +67,8 @@ final private[tournament] class Cached(
arena.Sheet(key.userId, _)
}
private val cache = cacheApi[SheetKey, Sheet]("tournament.sheet") {
_.initialCapacity(8192)
.expireAfterAccess(3 minutes)
private val cache = cacheApi[SheetKey, Sheet](8192, "tournament.sheet") {
_.expireAfterAccess(3 minutes)
.maximumSize(32768)
.buildAsyncFuture(compute)
}

View File

@ -234,9 +234,8 @@ final class JsonView(
"win" -> s.scores.count(_.res == arena.Sheet.ResWin)
)
private val cachableData = cacheApi[Tournament.ID, CachableData]("tournament.json.cachable") {
_.initialCapacity(16)
.expireAfterWrite(1 second)
private val cachableData = cacheApi[Tournament.ID, CachableData](16, "tournament.json.cachable") {
_.expireAfterWrite(1 second)
.buildAsyncFuture { id =>
for {
tour <- tournamentRepo byId id
@ -304,9 +303,8 @@ final class JsonView(
.add("title" -> light.flatMap(_.title))
}
private val podiumJsonCache = cacheApi[Tournament.ID, Option[JsArray]]("tournament.podiumJson") {
_.initialCapacity(32)
.expireAfterAccess(10 seconds)
private val podiumJsonCache = cacheApi[Tournament.ID, Option[JsArray]](32, "tournament.podiumJson") {
_.expireAfterAccess(10 seconds)
.maximumSize(256)
.buildAsyncFuture { id =>
tournamentRepo finishedById id flatMap {
@ -351,9 +349,8 @@ final class JsonView(
"p" -> Json.arr(u1, u2)
)
private val teamStandingCache = cacheApi[Tournament.ID, JsArray]("tournament.teamStanding") {
_.initialCapacity(4)
.expireAfterWrite(1 second)
private val teamStandingCache = cacheApi[Tournament.ID, JsArray](4, "tournament.teamStanding") {
_.expireAfterWrite(1 second)
.buildAsyncFuture { id =>
tournamentRepo.teamBattleOf(id) flatMap {
_.fold(fuccess(JsArray())) { battle =>
@ -384,9 +381,8 @@ final class JsonView(
)
}
private val teamInfoCache = cacheApi[(Tournament.ID, TeamID), Option[JsObject]]("tournament.teamInfo") {
_.initialCapacity(4)
.expireAfterWrite(5 seconds)
private val teamInfoCache = cacheApi[(Tournament.ID, TeamID), Option[JsObject]](4, "tournament.teamInfo") {
_.expireAfterWrite(5 seconds)
.maximumSize(32)
.buildAsyncFuture {
case (tourId, teamId) =>

View File

@ -452,9 +452,8 @@ final class TournamentApi(
socket.reload(tour.id) >>- publish()
}
private val tournamentTopCache = cacheApi[Tournament.ID, TournamentTop]("tournament.top") {
_.initialCapacity(16)
.refreshAfterWrite(3 second)
private val tournamentTopCache = cacheApi[Tournament.ID, TournamentTop](16, "tournament.top") {
_.refreshAfterWrite(3 second)
.expireAfterAccess(5 minutes)
.maximumSize(64)
.buildAsyncFuture { id =>

View File

@ -33,15 +33,13 @@ final class TournamentStandingApi(
else computeMaybe(tour.id, page)
} else compute(tour, page)
private val first = cacheApi[Tournament.ID, JsObject]("tournament.page.first") {
_.initialCapacity(16)
.expireAfterWrite(1 second)
private val first = cacheApi[Tournament.ID, JsObject](16, "tournament.page.first") {
_.expireAfterWrite(1 second)
.buildAsyncFuture { compute(_, 1) }
}
private val createdCache = cacheApi[(Tournament.ID, Int), JsObject]("tournament.page.createdCache") {
_.initialCapacity(2)
.expireAfterWrite(15 second)
private val createdCache = cacheApi[(Tournament.ID, Int), JsObject](2, "tournament.page.createdCache") {
_.expireAfterWrite(15 second)
.buildAsyncFuture {
case (tourId, page) => computeMaybe(tourId, page)
}

View File

@ -212,9 +212,8 @@ final private[video] class VideoApi(
private val max = 25
private val pathsCache = cacheApi[List[Tag], List[TagNb]]("video.paths") {
_.initialCapacity(32)
.expireAfterAccess(10 minutes)
private val pathsCache = cacheApi[List[Tag], List[TagNb]](32, "video.paths") {
_.expireAfterAccess(10 minutes)
.buildAsyncFuture { filterTags =>
val allPaths =
if (filterTags.isEmpty) allPopular map { tags =>