package org.opendaylight.controller.cluster.datastore;
import com.codahale.metrics.Timer;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
+import com.google.common.base.Ticker;
+import java.util.concurrent.TimeUnit;
import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
/**
* transaction
*/
public class TransactionRateLimitingCallback implements OperationCallback{
+ private static Ticker TICKER = Ticker.systemTicker();
+
+ private static enum State {
+ STOPPED,
+ RUNNING,
+ PAUSED
+ }
+
private final Timer commitTimer;
- private Timer.Context timerContext;
+ private long startTime;
+ private long elapsedTime;
+ private volatile State state = State.STOPPED;
TransactionRateLimitingCallback(ActorContext actorContext){
commitTimer = actorContext.getOperationTimer(ActorContext.COMMIT);
@Override
public void run() {
- timerContext = commitTimer.time();
+ Preconditions.checkState(state == State.STOPPED, "state is not STOPPED");
+ resume();
+ }
+
+ @Override
+ public void pause() {
+ if(state == State.RUNNING) {
+ elapsedTime += TICKER.read() - startTime;
+ state = State.PAUSED;
+ }
+ }
+
+ @Override
+ public void resume() {
+ if(state != State.RUNNING) {
+ startTime = TICKER.read();
+ state = State.RUNNING;
+ }
}
@Override
public void success() {
- Preconditions.checkState(timerContext != null, "Call run before success");
- timerContext.stop();
+ Preconditions.checkState(state != State.STOPPED, "state is STOPPED");
+ pause();
+ commitTimer.update(elapsedTime, TimeUnit.NANOSECONDS);
+ state = State.STOPPED;
}
@Override
// not going to be useful - so we leave it as it is
}
+ @VisibleForTesting
+ static void setTicker(Ticker ticker) {
+ TICKER = ticker;
+ }
}
\ No newline at end of file