abstract caches with AsyncCache, baked by spray LruCache
This commit is contained in:
parent
bbfaa7d58f
commit
1b5e6acc3a
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
27
modules/memo/src/main/AsyncCache.scala
Normal file
27
modules/memo/src/main/AsyncCache.scala
Normal 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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue