diff --git a/src/java/com/threerings/presents/server/PresentsClient.java b/src/java/com/threerings/presents/server/PresentsClient.java index 0c0e69e85..9b4196662 100644 --- a/src/java/com/threerings/presents/server/PresentsClient.java +++ b/src/java/com/threerings/presents/server/PresentsClient.java @@ -526,7 +526,7 @@ public class PresentsClient } /** - * Creates our incoming messaeg throttle. + * Creates our incoming message throttle. */ protected Throttle createIncomingMessageThrottle () { diff --git a/src/java/com/threerings/presents/server/VariableThrottle.java b/src/java/com/threerings/presents/server/VariableThrottle.java new file mode 100644 index 000000000..9e7b83088 --- /dev/null +++ b/src/java/com/threerings/presents/server/VariableThrottle.java @@ -0,0 +1,43 @@ +package com.threerings.presents.server; + +import com.samskivert.util.Throttle; + +/** + * Throttle subclass that allows changing the operation limit. + */ +public class VariableThrottle extends Throttle +{ + /** + * Creates a new updateable throttle. + */ + public VariableThrottle (int operations, long period) + { + super(operations, 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 + */ + public void updateOpLimit (int operations) + { + 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; + } +} diff --git a/tests/src/java/com/threerings/presents/server/TestVariableThrottle.java b/tests/src/java/com/threerings/presents/server/TestVariableThrottle.java new file mode 100644 index 000000000..ce324d6aa --- /dev/null +++ b/tests/src/java/com/threerings/presents/server/TestVariableThrottle.java @@ -0,0 +1,69 @@ +package com.threerings.presents.server; + +/** + * Test class to exercise the code in {@link VariableThrottle}. + */ +public class TestVariableThrottle +{ + /** + * Exercise the code in {@link VariableThrottle}. + */ + public static void main (String[] args) + { + 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. + */ + public static 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.updateOpLimit(10); + for (int ii = 0; ii < opCount; ++ii) { + throttle.throttleOp(time += 1); + } + System.out.println(" " + throttle.opsToString()); + throttle.updateOpLimit(5); + System.out.println(" " + throttle.opsToString()); + for (int ii = 0; ii < opCount; ++ii) { + throttle.throttleOp(time += 1); + } + System.out.println(" " + throttle.opsToString()); + throttle.updateOpLimit(10); + System.out.println(" " + throttle.opsToString()); + } + + /** + * Constructs a string representation of all operation time stamps, starting from the oldest. + */ + public static class TestThrottle extends VariableThrottle + { + 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; + } + } +}