package org.apache.cassandra.utils;
/**
* Limits rate of operations to be no more than opsSec by pausing current thread.
*
* It also tries to AVG ops during 10 seconds.
*
* Using it to limit stream In rate (otherwise it overloades node on decomission)
*
* @author Oleg Anastasyev<oa@odnoklassniki.ru>
*
*/
public class RateControl
{
private final int AVG_SECS=10;
private long lastSecond;
private int ops;
private long nanosPerOp;
/**
* @param opsSec ops Sec limit
*/
public RateControl(int opsSec)
{
this.nanosPerOp = 1000000000/opsSec;
}
/**
* Counts 1 operation, pausing thread if neccessary to meet rate limit
*/
public synchronized void control()
{
if (lastSecond==0L)
{
long last=System.nanoTime();
lastSecond=last;
ops=1;
return;
}
long now=System.nanoTime();
ops++;
long nowEstimated= lastSecond + nanosPerOp*ops;
if (nowEstimated>now+nanosPerOp/10) // dont pause, if delta is not so much <10% of total operation
{
// sleeping whole millis with sleep to conserve cpu
long millis=(nowEstimated-now) / 1000000;
if (millis>0)
millis=(nowEstimated-System.nanoTime()) / 1000000;
if (millis>0)
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// sleeping rest with nanosecond precision (sleep cannot sleep less than 1ms)
while (nowEstimated>System.nanoTime())
Thread.yield(); // gives pause from 40 till 100 microseconds
}
if (now>lastSecond + 1000000000*AVG_SECS)
{
ops=1;
lastSecond=now;
}
}
}