/** * Copyright 2014 Yahoo! Inc. 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. See accompanying * LICENSE file. */ package com.yahoo.sql4d.indexeragent.actors; import akka.actor.Cancellable; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author srikalyan */ public abstract class Throttler implements Cancellable, Runnable { private static final Logger log = LoggerFactory.getLogger(Throttler.class); private final int initialDelay; private final int msgsPerSecond; private final int maxMessagesAnyTime; private final AtomicBoolean cancel = new AtomicBoolean(false); private final Thread selfThread; public Throttler(int initialDelay, int msgsPerSecond, int maxMessagesAnyTime) { this.initialDelay = initialDelay; this.msgsPerSecond = msgsPerSecond; this.maxMessagesAnyTime = maxMessagesAnyTime; this.selfThread = new Thread(this); } public Cancellable startThrottling() { selfThread.start(); return this; } @Override public boolean cancel() { cancel.set(true); return cancel.get(); } @Override public boolean isCancelled() { return cancel.get(); } @Override public void run() { try { TimeUnit.SECONDS.sleep(initialDelay); } catch (InterruptedException ex) { log.warn("Throttler bootstrap interrupted ! {}", ex); } while (!isCancelled()) { try { int inProgressCount = getInProgressActionCount(); log.info("Current in progress {}, msgsPerSecond {}, maxMessagesAnyTime {}, ", inProgressCount, msgsPerSecond, maxMessagesAnyTime); if (inProgressCount >= maxMessagesAnyTime) { TimeUnit.SECONDS.sleep(1); } else { int p = (maxMessagesAnyTime - inProgressCount); if (p <= msgsPerSecond) { log.debug("Running action p={} times", p); runActionXTimes(p); } else { int q = p; // Lets say p = 11 and msgsPerSecond = 10 while (q > 0) { // q = 11 if (q > msgsPerSecond) { // All but last condition succeeds here. log.debug("Running action msgsPerSecond={} times", msgsPerSecond); runActionXTimes(msgsPerSecond); } else { // This occurs the last time i.e when q=1 log.debug("Running action q={} times", q); runActionXTimes(q);//hit overlord q times } TimeUnit.SECONDS.sleep(1); q = q - msgsPerSecond; } } } } catch (InterruptedException ex) { log.warn("Throttler interrupted ! {}", ex); } } } private void runActionXTimes(int n) { for (int i = 0;i < n;i++) { runAction(); } } public abstract int getInProgressActionCount(); public abstract void runAction(); }