/*
* Copyright (c) 2015 Spotify AB.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Copyright 2010-2013 Coda Hale and Yammer, Inc., 2014-2015 Dropwizard Team
* <p>
* It is licensed under the Apache 2.0 license.
* <p>
* The below link is a snapshot of the commit that this code was copied from, it includes licensing
* information. https://github.com/dropwizard/metrics/tree/e45597d00b972e530b0a79b95190615b4e031ec9
*/
package com.spotify.heroic.metrics;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
/**
* A meter metric which measures mean five-minute exponentially-weighted moving average
* throughputs.
*
* @see EWMA
*/
public class Meter {
private static final long TICK_INTERVAL = TimeUnit.SECONDS.toNanos(5);
private final LongAdder count = new LongAdder();
private final EWMA m5Rate = EWMA.fiveMinuteEWMA();
private final long startTime;
private final AtomicLong lastTick;
private final Clock clock;
/**
* Creates a new {@link Meter}.
*/
public Meter() {
this(Clock.systemClock());
}
/**
* Creates a new {@link Meter}.
*
* @param clock the clock to use for the meter ticks
*/
public Meter(Clock clock) {
this.clock = clock;
this.startTime = this.clock.getTick();
this.lastTick = new AtomicLong(startTime);
}
/**
* Mark the occurrence of an event.
*/
public void mark() {
mark(1);
}
/**
* Mark the occurrence of a given number of events.
*
* @param n the number of events
*/
public void mark(long n) {
tickIfNecessary();
count.add(n);
m5Rate.update(n);
}
private void tickIfNecessary() {
final long oldTick = lastTick.get();
final long newTick = clock.getTick();
final long age = newTick - oldTick;
if (age > TICK_INTERVAL) {
final long newIntervalStartTick = newTick - age % TICK_INTERVAL;
if (lastTick.compareAndSet(oldTick, newIntervalStartTick)) {
final long requiredTicks = age / TICK_INTERVAL;
for (long i = 0; i < requiredTicks; i++) {
m5Rate.tick();
}
}
}
}
public long getCount() {
return count.sum();
}
public double getFiveMinuteRate() {
tickIfNecessary();
return m5Rate.getRate(TimeUnit.SECONDS);
}
}