abstract caches with AsyncCache, baked by spray LruCache

This commit is contained in:
Thibault Duplessis 2013-05-19 09:55:16 -03:00
parent bbfaa7d58f
commit 1b5e6acc3a
11 changed files with 73 additions and 118 deletions

View file

@ -15,7 +15,7 @@ final class BookmarkApi(
gameOption ?? { game
BookmarkRepo.toggle(gameId, userId) flatMap { bookmarked
GameRepo.incBookmarks(gameId, bookmarked.fold(1, -1)) >>
fuccess(cached invalidateUserId userId)
(cached.gameIds remove userId)
}
}
}

View file

@ -1,23 +1,16 @@
package lila.bookmark
import spray.caching.{ LruCache, Cache }
import lila.memo.AsyncCache
private[bookmark] final class Cached {
val gameIds = AsyncCache(
(userId: String) BookmarkRepo gameIdsByUserId userId map (_.toSet),
maxCapacity = 50000)
def bookmarked(gameId: String, userId: String): Fu[Boolean] =
userGameIds(userId) map (_ contains gameId)
gameIds(userId) map (_ contains gameId)
def count(userId: String): Fu[Int] =
userGameIds(userId) map (_.size)
def invalidateUserId(userId: String) {
gameIdsCache.remove(userId)
}
private def userGameIds(userId: String): Fu[Set[String]] =
gameIdsCache.fromFuture(userId.toLowerCase) {
BookmarkRepo gameIdsByUserId userId.toLowerCase map (_.toSet)
}
private val gameIdsCache: Cache[Set[String]] = LruCache(maxCapacity = 99999)
gameIds(userId) map (_.size)
}

View file

@ -1,39 +1,10 @@
package lila.friend
import lila.user.User
import scala.collection.mutable
import lila.memo.AsyncCache
private[friend] final class Cached {
def friendIds(userId: String): List[String] = FriendIdsCache(userId)
def invalidateFriendIds(userId: String) { FriendIdsCache invalidate userId }
val friendIds = AsyncCache(FriendRepo.friendUserIds, maxCapacity = 5000)
def nbRequests(userId: String): Int = NbRequestsCache(userId)
def invalidateNbRequests(userId: String) { NbRequestsCache invalidate userId }
private object NbRequestsCache {
//TODO fix that crap
def apply(userId: String): Int = cache.getOrElseUpdate(userId,
(RequestRepo countByFriendId userId).await
)
def invalidate(userId: String) { cache -= userId }
// userId => number
private val cache = mutable.Map[String, Int]()
}
private object FriendIdsCache {
def apply(userId: String): List[String] = cache.getOrElseUpdate(userId,
(FriendRepo friendUserIds userId).await
)
def invalidate(userId: String) { cache -= userId }
// id => name
private val cache = mutable.Map[String, List[String]]()
}
val nbRequests = AsyncCache(RequestRepo.countByFriendId, maxCapacity = 5000)
}

View file

@ -4,11 +4,7 @@ import org.scala_tools.time.Imports._
import lila.user.{ User, UserRepo }
// final class FriendApi(
// friendRepo: FriendRepo,
// requestRepo: RequestRepo,
// userRepo: UserRepo,
// cached: Cached) {
// final class FriendApi( cached: Cached) {
// def areFriends(u1: String, u2: String) = friendIds(u1) contains u2

View file

@ -2,21 +2,17 @@ package lila.game
import lila.db.api.$count
import tube.gameTube
import lila.memo.AsyncCache
import scala.concurrent.duration._
import spray.caching.{ LruCache, Cache }
import play.api.libs.json.JsObject
private[game] final class Cached(ttl: Duration) {
def nbGames: Fu[Int] = count(_.all)
def nbMates: Fu[Int] = count(_.mate)
def nbPopular: Fu[Int] = count(_.popular)
def nbImported: Fu[Int] = count(_.imported)
def nbGames: Fu[Int] = count(Query.all)
def nbMates: Fu[Int] = count(Query.mate)
def nbPopular: Fu[Int] = count(Query.popular)
def nbImported: Fu[Int] = count(Query.imported)
private def count(selector: Query.type JsObject) =
selector(Query) |> { sel cache.fromFuture(sel)($count(sel)) }
private val cache: Cache[Int] = LruCache(timeToLive = ttl)
private val count = AsyncCache((o: JsObject) $count(o), timeToLive = ttl)
}

View file

@ -0,0 +1,27 @@
package lila.memo
import scala.concurrent.duration._
import spray.caching.{ LruCache, Cache }
final class AsyncCache[K, V] private (cache: Cache[V], f: K Fu[V]) {
def apply(k: K): Fu[V] = cache.fromFuture(k)(f(k))
def get(k: K): Option[Fu[V]] = cache get k
def remove(k: K): Funit = fuccess(cache remove k).void
def clear: Funit = fuccess(cache.clear)
}
object AsyncCache {
def apply[K, V](
f: K Fu[V],
maxCapacity: Int = 500,
initialCapacity: Int = 16,
timeToLive: Duration = Duration.Zero,
timeToIdle: Duration = Duration.Zero) = new AsyncCache(
cache = LruCache(maxCapacity, initialCapacity, timeToLive, timeToIdle),
f = f)
}

View file

@ -1,38 +1,14 @@
package lila.team
import lila.user.User
import lila.memo.AsyncCache
import spray.caching.{ LruCache, Cache }
private[team] final class Cached(capacity: Int) {
final class Cached(capacity: Int) {
val name = AsyncCache(TeamRepo.name, maxCapacity = capacity)
object name {
val teamIds = AsyncCache(MemberRepo.teamIdsByUser, maxCapacity = capacity)
private val cache: Cache[Option[String]] = LruCache(maxCapacity = capacity)
def apply(id: String): Fu[Option[String]] =
cache.fromFuture(id)(TeamRepo name id)
}
object teamIds {
private val cache: Cache[List[String]] = LruCache(maxCapacity = capacity)
def apply(userId: String): Fu[List[String]] =
cache.fromFuture(userId)(MemberRepo teamIdsByUser userId)
def invalidate(userId: String): Funit = cache.remove(userId) ?? (_.void)
}
object nbRequests {
private val cache: Cache[Int] = LruCache(maxCapacity = capacity)
def apply(userId: String): Fu[Int] =
cache.fromFuture(userId) {
TeamRepo teamIdsByCreator userId flatMap RequestRepo.countByTeams
}
def invalidate(userId: String): Funit = cache.remove(userId) ?? (_.void)
}
val nbRequests = AsyncCache(
(userId: String) TeamRepo teamIdsByCreator userId flatMap RequestRepo.countByTeams,
maxCapacity = capacity)
}

View file

@ -31,7 +31,7 @@ final class TeamApi(
createdBy = me)
$insert(team) >>
MemberRepo.add(team.id, me.id) >>
(cached.teamIds invalidate me.id) >>-
(cached.teamIds remove me.id) >>-
(forum ! MakeTeam(team.id, team.name)) >>-
(indexer ! InsertTeam(team)) inject team
}
@ -91,13 +91,13 @@ final class TeamApi(
_ ?? {
val request = Request.make(team = team.id, user = user.id, message = setup.message)
val rwu = RequestWithUser(request, user)
$insert(request) >> (cached.nbRequests invalidate team.createdBy)
$insert(request) >> (cached.nbRequests remove team.createdBy)
}
}
def processRequest(team: Team, request: Request, accept: Boolean): Funit = for {
_ $remove(request)
_ cached.nbRequests invalidate team.createdBy
_ cached.nbRequests remove team.createdBy
userOption $find.byId[User](request.user)
_ userOption.filter(_ accept).??(user
doJoin(team, user.id) >>- notifier.acceptRequest(team, request)
@ -109,7 +109,7 @@ final class TeamApi(
(!belongs) ?? {
MemberRepo.add(team.id, userId) >>
TeamRepo.incMembers(team.id, +1) >>
(cached.teamIds invalidate userId)
(cached.teamIds remove userId)
}
}
@ -125,7 +125,7 @@ final class TeamApi(
_ ?? {
MemberRepo.remove(team.id, userId) >>
TeamRepo.incMembers(team.id, -1) >>
(cached.teamIds invalidate userId)
(cached.teamIds remove userId)
}
}

View file

@ -1,13 +1,15 @@
package lila.user
import scala.concurrent.duration._
import lila.db.api.$count
import tube.userTube
import lila.memo.AsyncCache
import spray.caching.{ LruCache, Cache }
import play.api.libs.json.JsObject
import scala.concurrent.duration._
final class Cached(ttl: Duration) {
def username(id: String): Fu[Option[String]] =
usernameCache.fromFuture(id)(UserRepo usernameById id)
val username = AsyncCache(UserRepo.usernameById, maxCapacity = 50000)
def usernameOrAnonymous(id: String): Fu[String] =
username(id) map (_ | User.anonymous)
@ -15,10 +17,7 @@ final class Cached(ttl: Duration) {
def usernameOrAnonymous(id: Option[String]): Fu[String] =
id.fold(fuccess(User.anonymous))(usernameOrAnonymous)
def countEnabled: Fu[Int] = countEnabledCache.fromFuture(true)(UserRepo.countEnabled)
val count = AsyncCache((o: JsObject) $count(o), timeToLive = ttl)
// id => username
private val usernameCache: Cache[Option[String]] = LruCache(maxCapacity = 99999)
private val countEnabledCache: Cache[Int] = LruCache(timeToLive = ttl)
def countEnabled: Fu[Int] = count(UserRepo.enabledQuery)
}

View file

@ -105,8 +105,6 @@ object UserRepo {
}
} yield userOption
def countEnabled: Fu[Int] = $count(enabledQuery)
def usernamesLike(username: String, max: Int = 10): Fu[List[String]] = {
import java.util.regex.Matcher.quoteReplacement
val escaped = """^([\w-]*).*$""".r.replaceAllIn(normalize(username), m quoteReplacement(m group 1))

View file

@ -43,7 +43,7 @@ object ApplicationBuild extends Build {
)
lazy val memo = project("memo", Seq(common)).settings(
libraryDependencies ++= Seq(guava, findbugs) ++ provided(play.api)
libraryDependencies ++= Seq(guava, findbugs, spray.caching) ++ provided(play.api)
)
lazy val db = project("db", Seq(common)).settings(
@ -66,13 +66,12 @@ object ApplicationBuild extends Build {
lazy val user = project("user", Seq(common, memo, db, hub, chess)).settings(
libraryDependencies ++= provided(
play.api, play.test, reactivemongo, playReactivemongo,
hasher, spray.caching)
play.api, play.test, reactivemongo, playReactivemongo, hasher)
)
lazy val game = project("game", Seq(common, db, hub, user, chess)).settings(
lazy val game = project("game", Seq(common, memo, db, hub, user, chess)).settings(
libraryDependencies ++= provided(
play.api, reactivemongo, playReactivemongo, spray.caching)
play.api, reactivemongo, playReactivemongo)
)
lazy val gameSearch = project("gameSearch", Seq(common, hub, chess, search, game, analyse)).settings(
@ -136,9 +135,9 @@ object ApplicationBuild extends Build {
play.api, reactivemongo, playReactivemongo, scalastic)
)
lazy val team = project("team", Seq(common, db, user, forum, security, hub)).settings(
lazy val team = project("team", Seq(common, memo, db, user, forum, security, hub)).settings(
libraryDependencies ++= provided(
play.api, reactivemongo, playReactivemongo, spray.caching)
play.api, reactivemongo, playReactivemongo)
)
lazy val teamSearch = project("teamSearch", Seq(common, hub, team, search)).settings(
@ -151,9 +150,9 @@ object ApplicationBuild extends Build {
play.api, reactivemongo, playReactivemongo, jgit)
)
lazy val bookmark = project("bookmark", Seq(common, db, hub, user, game)).settings(
lazy val bookmark = project("bookmark", Seq(common, memo, db, hub, user, game)).settings(
libraryDependencies ++= provided(
play.api, play.test, reactivemongo, playReactivemongo, spray.caching)
play.api, play.test, reactivemongo, playReactivemongo)
)
lazy val wiki = project("wiki", Seq(common, db)).settings(