diff --git a/src/java/com/samskivert/util/Throttle.java b/src/java/com/samskivert/util/Throttle.java index bd571287..a54e57f1 100644 --- a/src/java/com/samskivert/util/Throttle.java +++ b/src/java/com/samskivert/util/Throttle.java @@ -63,6 +63,35 @@ public class Throttle _period = period; } + /** + * Updates the number of operations for this throttle to a new maximum, retaining the current + * history of operations if the limit is being increased and truncating the oldest operations + * if the limit is decreased. + * + * @param operations the new maximum number of operations. + * @param period the new period. + */ + public void reinit (int operations, long period) + { + long[] ops = new long[operations]; + if (operations > _ops.length) { + // copy to a larger buffer, leaving zeroes at the beginning + int lastOp = _lastOp + operations - _ops.length; + System.arraycopy(_ops, 0, ops, 0, _lastOp); + System.arraycopy(_ops, _lastOp, ops, lastOp, _ops.length - _lastOp); + + } else if (operations < _ops.length) { + // copy to a smaller buffer, truncating older operations + int lastOp = (_lastOp + _ops.length - operations) % _ops.length; + int endCount = Math.min(_ops.length - lastOp, operations); + System.arraycopy(_ops, lastOp, ops, 0, endCount); + System.arraycopy(_ops, 0, ops, endCount, operations - endCount); + _lastOp = 0; + } + _ops = ops; + _period = period; + } + /** * Registers an attempt at an operation and returns true if the operation should be performed * or false if it should be throttled (meaning N operations have already been performed in the @@ -134,6 +163,13 @@ public class Throttle return _ops[(_lastOp + _ops.length - 1) % _ops.length]; } + @Override // from Object + public String toString () + { + long oldest = System.currentTimeMillis() - _ops[_lastOp]; + return _ops.length + " ops per " + _period + "ms (oldest " + oldest + ")"; + } + /** * Used for testing. */ diff --git a/src/java/com/samskivert/util/tests/ThrottleTest.java b/src/java/com/samskivert/util/tests/ThrottleTest.java new file mode 100644 index 00000000..5373aa68 --- /dev/null +++ b/src/java/com/samskivert/util/tests/ThrottleTest.java @@ -0,0 +1,108 @@ +// +// $Id$ +// +// samskivert library - useful routines for java programs +// Copyright (C) 2001-2008 Michael Bayne +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.util.tests; + +import junit.framework.Test; +import junit.framework.TestCase; + +import com.samskivert.util.Throttle; + +/** + * A test case for {@link Throttle}. + */ +public class ThrottleTest extends TestCase +{ + public static Test suite () + { + return new ThrottleTest(); + } + + public static void main (String[] args) + { + ThrottleTest test = new ThrottleTest(); + test.runTest(); + } + + public ThrottleTest () + { + super(ThrottleTest.class.getName()); + } + + @Override + public void runTest () + { + testUpdate(4); + testUpdate(5); + testUpdate(6); + testUpdate(7); + testUpdate(8); + } + + /** + * Calls the {@link VariableThrottle#updateOpLimit} function a few times, interspersed with + * calls to add operations. Prints the operations contained in the throttle after each change. + */ + protected void testUpdate (int opCount) + { + // set up a throttle for 5 ops per millisecond + TestThrottle throttle = new TestThrottle(5, 1); + System.out.println("Testing updates with " + opCount + " operations"); + long time = 0; + for (int ii = 0; ii < opCount; ++ii) { + throttle.throttleOp(time += 1); + } + System.out.println(" " + throttle.opsToString()); + throttle.reinit(10, 1); + for (int ii = 0; ii < opCount; ++ii) { + throttle.throttleOp(time += 1); + } + System.out.println(" " + throttle.opsToString()); + throttle.reinit(5, 1); + System.out.println(" " + throttle.opsToString()); + for (int ii = 0; ii < opCount; ++ii) { + throttle.throttleOp(time += 1); + } + System.out.println(" " + throttle.opsToString()); + throttle.reinit(10, 1); + System.out.println(" " + throttle.opsToString()); + } + + /** + * Constructs a string representation of all operation time stamps, starting from the oldest. + */ + public static class TestThrottle extends Throttle + { + public TestThrottle (int maxOps, long period) + { + super(maxOps, period); + } + + public String opsToString () + { + String hist = String.valueOf(_ops[_lastOp]); + for (int ii = 1; ii < _ops.length; ++ii) { + long tn = _ops[(_lastOp + ii) % _ops.length]; + hist += ", " + String.valueOf(tn); + } + return hist; + } + } +}