MINOR: Simplify SensorAccess usage

I was investigating an exception in this code and found a few
opportunities for making it clearer.

I also added the `out` folder to `.gitignore` as IntelliJ sometimes
uses that as the build folder.

Author: Ismael Juma <ismael@juma.me.uk>

Reviewers: Rajini Sivaram <rajinisivaram@googlemail.com>

Closes #3552 from ijuma/minor-quota-improvements
This commit is contained in:
Ismael Juma 2017-07-20 14:01:11 +01:00
parent 272956f03a
commit 84d2b6a01c
4 changed files with 29 additions and 36 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@ dist
target/ target/
build/ build/
build_eclipse/ build_eclipse/
out/
.gradle/ .gradle/
lib_managed/ lib_managed/
src_managed/ src_managed/

View File

@ -138,10 +138,12 @@ class ClientQuotaManager(private val config: ClientQuotaManagerConfig,
private val time: Time) extends Logging { private val time: Time) extends Logging {
private val overriddenQuota = new ConcurrentHashMap[QuotaId, Quota]() private val overriddenQuota = new ConcurrentHashMap[QuotaId, Quota]()
private val staticConfigClientIdQuota = Quota.upperBound(config.quotaBytesPerSecondDefault) private val staticConfigClientIdQuota = Quota.upperBound(config.quotaBytesPerSecondDefault)
@volatile private var quotaTypesEnabled = if (config.quotaBytesPerSecondDefault == Long.MaxValue) QuotaTypes.NoQuotas else QuotaTypes.ClientIdQuotaEnabled @volatile private var quotaTypesEnabled =
if (config.quotaBytesPerSecondDefault == Long.MaxValue) QuotaTypes.NoQuotas
else QuotaTypes.ClientIdQuotaEnabled
private val lock = new ReentrantReadWriteLock() private val lock = new ReentrantReadWriteLock()
private val delayQueue = new DelayQueue[ThrottledResponse]() private val delayQueue = new DelayQueue[ThrottledResponse]()
private val sensorAccessor = new SensorAccess private val sensorAccessor = new SensorAccess(lock, metrics)
val throttledRequestReaper = new ThrottledRequestReaper(delayQueue) val throttledRequestReaper = new ThrottledRequestReaper(delayQueue)
private val delayQueueSensor = metrics.sensor(quotaType + "-delayQueue") private val delayQueueSensor = metrics.sensor(quotaType + "-delayQueue")
@ -392,24 +394,19 @@ class ClientQuotaManager(private val config: ClientQuotaManagerConfig,
sensorAccessor.getOrCreate( sensorAccessor.getOrCreate(
getQuotaSensorName(clientQuotaEntity.quotaId), getQuotaSensorName(clientQuotaEntity.quotaId),
ClientQuotaManagerConfig.InactiveSensorExpirationTimeSeconds, ClientQuotaManagerConfig.InactiveSensorExpirationTimeSeconds,
lock, metrics, clientRateMetricName(clientQuotaEntity.sanitizedUser, clientQuotaEntity.clientId),
() => clientRateMetricName(clientQuotaEntity.sanitizedUser, clientQuotaEntity.clientId), Some(getQuotaMetricConfig(clientQuotaEntity.quota)),
() => getQuotaMetricConfig(clientQuotaEntity.quota), new Rate
() => measurableStat
), ),
sensorAccessor.getOrCreate(getThrottleTimeSensorName(clientQuotaEntity.quotaId), sensorAccessor.getOrCreate(getThrottleTimeSensorName(clientQuotaEntity.quotaId),
ClientQuotaManagerConfig.InactiveSensorExpirationTimeSeconds, ClientQuotaManagerConfig.InactiveSensorExpirationTimeSeconds,
lock, throttleMetricName(clientQuotaEntity),
metrics, None,
() => throttleMetricName(clientQuotaEntity), new Avg
() => null,
() => new Avg()
) )
) )
} }
private def measurableStat: MeasurableStat = new Rate()
private def getThrottleTimeSensorName(quotaId: QuotaId): String = quotaType + "ThrottleTime-" + quotaId.sanitizedUser.getOrElse("") + ':' + quotaId.clientId.getOrElse("") private def getThrottleTimeSensorName(quotaId: QuotaId): String = quotaType + "ThrottleTime-" + quotaId.sanitizedUser.getOrElse("") + ':' + quotaId.clientId.getOrElse("")
private def getQuotaSensorName(quotaId: QuotaId): String = quotaType + "-" + quotaId.sanitizedUser.getOrElse("") + ':' + quotaId.clientId.getOrElse("") private def getQuotaSensorName(quotaId: QuotaId): String = quotaType + "-" + quotaId.sanitizedUser.getOrElse("") + ':' + quotaId.clientId.getOrElse("")
@ -425,10 +422,9 @@ class ClientQuotaManager(private val config: ClientQuotaManagerConfig,
sensorAccessor.getOrCreate( sensorAccessor.getOrCreate(
sensorName, sensorName,
ClientQuotaManagerConfig.InactiveSensorExpirationTimeSeconds, ClientQuotaManagerConfig.InactiveSensorExpirationTimeSeconds,
lock, metrics, metricName,
() => metricName, None,
() => null, new Rate
() => measurableStat
) )
} }

View File

@ -74,8 +74,9 @@ class ReplicationQuotaManager(val config: ReplicationQuotaManagerConfig,
private val lock = new ReentrantReadWriteLock() private val lock = new ReentrantReadWriteLock()
private val throttledPartitions = new ConcurrentHashMap[String, Seq[Int]]() private val throttledPartitions = new ConcurrentHashMap[String, Seq[Int]]()
private var quota: Quota = null private var quota: Quota = null
private val sensorAccess = new SensorAccess private val sensorAccess = new SensorAccess(lock, metrics)
private val rateMetricName = metrics.metricName("byte-rate", replicationType.toString, s"Tracking byte-rate for ${replicationType}") private val rateMetricName = metrics.metricName("byte-rate", replicationType.toString,
s"Tracking byte-rate for ${replicationType}")
/** /**
* Update the quota * Update the quota
@ -194,11 +195,9 @@ class ReplicationQuotaManager(val config: ReplicationQuotaManagerConfig,
sensorAccess.getOrCreate( sensorAccess.getOrCreate(
replicationType.toString, replicationType.toString,
InactiveSensorExpirationTimeSeconds, InactiveSensorExpirationTimeSeconds,
lock, rateMetricName,
metrics, Some(getQuotaMetricConfig(quota)),
() => rateMetricName, new SimpleRate
() => getQuotaMetricConfig(quota),
() => new SimpleRate()
) )
} }
} }

View File

@ -16,10 +16,10 @@
*/ */
package kafka.server package kafka.server
import java.util.concurrent.locks.ReentrantReadWriteLock import java.util.concurrent.locks.ReadWriteLock
import org.apache.kafka.common.MetricName import org.apache.kafka.common.MetricName
import org.apache.kafka.common.metrics.{Metrics, Sensor, MeasurableStat, MetricConfig} import org.apache.kafka.common.metrics.{MeasurableStat, MetricConfig, Metrics, Sensor}
/** /**
* Class which centralises the logic for creating/accessing sensors. * Class which centralises the logic for creating/accessing sensors.
@ -27,9 +27,10 @@ import org.apache.kafka.common.metrics.{Metrics, Sensor, MeasurableStat, MetricC
* *
* The later arguments are passed as methods as they are only called when the sensor is instantiated. * The later arguments are passed as methods as they are only called when the sensor is instantiated.
*/ */
class SensorAccess { class SensorAccess(lock: ReadWriteLock, metrics: Metrics) {
def getOrCreate(sensorName: String, expirationTime: Long, lock: ReentrantReadWriteLock, metrics: Metrics, metricName: () => MetricName, config: () => MetricConfig, measure: () => MeasurableStat): Sensor = { def getOrCreate(sensorName: String, expirationTime: Long,
metricName: => MetricName, config: => Option[MetricConfig], measure: => MeasurableStat): Sensor = {
var sensor: Sensor = null var sensor: Sensor = null
/* Acquire the read lock to fetch the sensor. It is safe to call getSensor from multiple threads. /* Acquire the read lock to fetch the sensor. It is safe to call getSensor from multiple threads.
@ -41,12 +42,8 @@ class SensorAccess {
* at which point it is safe to read * at which point it is safe to read
*/ */
lock.readLock().lock() lock.readLock().lock()
try { try sensor = metrics.getSensor(sensorName)
sensor = metrics.getSensor(sensorName) finally lock.readLock().unlock()
}
finally {
lock.readLock().unlock()
}
/* If the sensor is null, try to create it else return the existing sensor /* If the sensor is null, try to create it else return the existing sensor
* The sensor can be null, hence the null checks * The sensor can be null, hence the null checks
@ -64,8 +61,8 @@ class SensorAccess {
// ensure that we initialise `ClientSensors` with non-null parameters. // ensure that we initialise `ClientSensors` with non-null parameters.
sensor = metrics.getSensor(sensorName) sensor = metrics.getSensor(sensorName)
if (sensor == null) { if (sensor == null) {
sensor = metrics.sensor(sensorName, config(), expirationTime) sensor = metrics.sensor(sensorName, config.orNull, expirationTime)
sensor.add(metricName(), measure()) sensor.add(metricName, measure)
} }
} finally { } finally {
lock.writeLock().unlock() lock.writeLock().unlock()