package com.linkedin.databus.core.util;
import com.linkedin.databus.core.DbusConstants;
/*
*
* Copyright 2013 LinkedIn Corp. All rights reserved
*
* Licensed 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.
*
*/
/**
* A class that can be used to monitor rate of events in a sequence of intervals
*/
public class RateMonitor
{
private final String _name;
private long _startTime;
private long _numTicks;
private double _rate;
private long _durationSoFar;
private State _state;
/*
* Rate Monitor internal state
*/
private enum State
{
INIT,
STARTED,
SUSPENDED,
RESUMED,
STOPPED
}
public RateMonitor(String name)
{
_name = name;
_startTime = -1;
_numTicks = 0;
_state = State.INIT;
}
/*
* @return true if the Monitor has been started
*/
public boolean started()
{
return (_startTime > 0);
}
/*
* Suspends the started/resumed monitor
*/
public void suspend()
{
if ( (_state == State.STARTED ) ||
(_state == State.RESUMED))
{
_durationSoFar += (getNanoTime() - _startTime);
_startTime = 0;
_state = State.SUSPENDED;
}
}
/*
* Resumes the suspended monitor
*
*/
public void resume()
{
if ( _state == State.SUSPENDED)
{
_startTime = getNanoTime();
_state = State.RESUMED;
}
}
/*
* Initializes and Starts the Monitor.
*/
public void start()
{
_startTime = getNanoTime();
_durationSoFar = 0;
_numTicks = 0;
_state = State.STARTED;
}
/*
* Increment the monitored event by one
*/
public void tick()
{
assert( ( _state != State.STOPPED ) &&
(_state != State.SUSPENDED));
_numTicks ++;
}
/*
* Increment the monitored event by ticks
*
* @param ticks : Number of events to be added
*/
public void ticks(long ticks)
{
assert( ( _state != State.STOPPED ) &&
(_state != State.SUSPENDED));
_numTicks += ticks;
}
/*
* @return the rate of events discounting the time it was in suspended/stopped state
*
*/
public double getRate()
{
long duration = getDuration();
if (_numTicks > 1000000000)
{
_rate = 1000000000 * ((double)_numTicks / (double) duration );
}
else
{
_rate = _numTicks * 1000000000.0 / duration;
}
return _rate;
}
/*
* @return the latency/duration discounting the time it was in suspended/stopped state
*/
public long getDuration()
{
long duration = 0;
switch ( _state)
{
case STARTED : duration = getNanoTime() - _startTime;
break;
case RESUMED : duration = getNanoTime() - _startTime + _durationSoFar;
break;
case STOPPED :
case SUSPENDED : duration = _durationSoFar;
break;
case INIT : throw new RuntimeException("RateMonitor not started !!");
}
return duration;
}
/*
* Returns the number of ticks
*/
public long getNumTicks()
{
return _numTicks;
}
/*
* Stops the monitor. Equivalent to suspend state except that it cannot be resumed
*/
public void stop()
{
if ( _state != State.SUSPENDED)
_durationSoFar += (getNanoTime() - _startTime);
_state = State.STOPPED;
}
@Override
public String toString()
{
return "RateMonitor [_name=" + _name + ", _numTicks=" + _numTicks + ", _rate="
+ _rate + ", _durationSoFar=" + _durationSoFar + ", state = " + _state + "]";
}
/*
* @return the current State of the RateMonitor
*/
public State getState()
{
return _state;
}
public boolean isStarted()
{
return _state == State.STARTED;
}
public long getNanoTime()
{
return System.nanoTime();
}
public void sleep(long msec) throws InterruptedException
{
Thread.sleep(msec);
}
/**
* A rate monitor that mocks time to avoid ambiguity to running unit tests
*/
public static class MockRateMonitor extends RateMonitor
{
private long _currentTimeInNs = 0L;
public MockRateMonitor(String name)
{
super(name);
}
@Override
public long getNanoTime()
{
return _currentTimeInNs;
}
public void setNanoTime(long ns)
{
_currentTimeInNs = ns;
}
@Override
public void sleep(long msec) throws InterruptedException
{
_currentTimeInNs += (msec * DbusConstants.NUM_NSECS_IN_MSEC);
}
}
}