com.twitter.finagle.pool.CachingPool.scala Maven / Gradle / Ivy
The newest version!
package com.twitter.finagle.pool
import com.twitter.finagle.stats.{NullStatsReceiver, StatsReceiver}
import com.twitter.finagle.util.Cache
import com.twitter.finagle.{
ClientConnection, Service, ServiceClosedException, ServiceFactory, ServiceProxy
}
import com.twitter.util.{Future, Time, Duration, Timer}
import scala.annotation.tailrec
/**
* A pool that temporarily caches items from the underlying one, up to
* the given timeout amount of time.
*/
private[finagle] class CachingPool[Req, Rep](
factory: ServiceFactory[Req, Rep],
cacheSize: Int,
ttl: Duration,
timer: Timer,
statsReceiver: StatsReceiver = NullStatsReceiver)
extends ServiceFactory[Req, Rep]
{
private[this] val cache =
new Cache[Service[Req, Rep]](cacheSize, ttl, timer, Some(_.close()))
@volatile private[this] var isOpen = true
private[this] val sizeGauge =
statsReceiver.addGauge("pool_cached") { cache.size }
private[this] class WrappedService(underlying: Service[Req, Rep])
extends ServiceProxy[Req, Rep](underlying)
{
override def close(deadline: Time) =
if (this.isAvailable && CachingPool.this.isOpen) {
cache.put(underlying)
Future.Done
} else
underlying.close(deadline)
}
@tailrec
private[this] def get(): Option[Service[Req, Rep]] = {
cache.get() match {
case s@Some(service) if service.isAvailable => s
case Some(service) /* unavailable */ => service.close(); get()
case None => None
}
}
def apply(conn: ClientConnection): Future[Service[Req, Rep]] = synchronized {
if (!isOpen) Future.exception(new ServiceClosedException) else {
get() match {
case Some(service) =>
Future.value(new WrappedService(service))
case None =>
factory(conn) map { new WrappedService(_) }
}
}
}
def close(deadline: Time) = synchronized {
isOpen = false
cache.evictAll()
factory.close(deadline)
}
override def isAvailable = isOpen && factory.isAvailable
override val toString = "caching_pool_%s".format(factory.toString)
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy