All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.finagle.stats.CumulativeGauge.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.finagle.stats

import scala.ref.WeakReference
import scala.collection.mutable.HashMap

/**
 * CumulativeGauge provides a gauge that is composed of the (addition)
 * of several underlying gauges. It follows the weak reference
 * semantics of Gauges as outlined in StatsReceiver.
 */
private[finagle] trait CumulativeGauge {
  private[this] case class UnderlyingGauge(f: () => Float) extends Gauge {
    def remove() { removeGauge(this) }
  }

  @volatile private[this] var underlying: List[WeakReference[UnderlyingGauge]] = Nil

  /**
   * Returns a buffered version of the current gauges
   */
  private[this] def get(): Seq[UnderlyingGauge] = {
    removeGauge(null)  // GC.
    underlying map { _.get } flatten
  }

  private[this] def removeGauge(underlyingGauge: UnderlyingGauge) = synchronized {
    // This does a GC also.
    underlying = underlying filter { _.get map { _ ne underlyingGauge } getOrElse false }
    if (underlying.isEmpty)
      deregister()
  }

  def addGauge(f: => Float): Gauge = synchronized {
    val shouldRegister = underlying.isEmpty
    val underlyingGauge = UnderlyingGauge(() => f)
    underlying ::= new WeakReference(underlyingGauge)
    if (shouldRegister)
      register()
    underlyingGauge
  }

  def getValue = get() map { _.f() } sum

  /**
   * These need to be implemented by the gauge provider. They indicate
   * when the gauge needs to be registered & deregistered.
   *
   * Special care must be taken in implementing these so that they are free
   * of race conditions.
   */
  def register(): Unit
  def deregister(): Unit
}

trait StatsReceiverWithCumulativeGauges extends StatsReceiver {
  private[this] val gaugeMap = new HashMap[Seq[String], CumulativeGauge]

  /**
   * The StatsReceiver implements these. They provide the cumulated
   * gauges.
   */
  protected[this] def registerGauge(name: Seq[String], f: => Float)
  protected[this] def deregisterGauge(name: Seq[String])

  def addGauge(name: String*)(f: => Float) = synchronized {
    val cumulativeGauge = gaugeMap getOrElseUpdate(name, {
      new CumulativeGauge {
        def register()   = StatsReceiverWithCumulativeGauges.this.registerGauge(name, getValue)
        def deregister() = StatsReceiverWithCumulativeGauges.this synchronized {
          gaugeMap.remove(name)
          StatsReceiverWithCumulativeGauges.this.deregisterGauge(name)
        }
      }
    })

    cumulativeGauge.addGauge(f)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy