/**
* The MIT License
* Copyright (c) 2014 JMXTrans Team
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jmxtrans.core.output.support.pool;
import java.util.concurrent.TimeUnit;
import stormpot.Expiration;
import stormpot.Poolable;
import stormpot.SlotInfo;
/**
* This is the standard time based {@link Expiration}. It will invalidate
* objects based on about how long ago they were allocated.
*
* @author Chris Vest <mr.chrisvest@gmail.com>
* @since 2.2
*/
// TODO 3.0 make class final
// FIXME: This class has been copied from stormpot and slightly modified. It should be replaced by upstream as soon as
// https://github.com/chrisvest/stormpot/pull/95 is release. Probably with stormpot 2.4.
public class JmxTransTimeSpreadExpiration<T extends Poolable> implements Expiration<T> {
private final long lowerBoundMillis;
private final long upperBoundMillis;
private final TimeUnit unit;
/**
* Construct a new Expiration that will invalidate objects that are older
* than the given lower bound, before they get older than the upper bound,
* in the given time unit.
*
* If the `lowerBound` is less than 1, the `upperBound` is less than the
* `lowerBound`, or the `unit` is `null`, then an
* {@link java.lang.IllegalArgumentException} will be thrown.
*
* @param lowerBound Poolables younger than this, in the given unit, are not
* considered expired. This value must be at least 1.
* @param upperBound Poolables older than this, in the given unit, are always
* considered expired. This value must be greater than the
* lowerBound.
* @param unit The {@link TimeUnit} of the bounds values. Never `null`.
*/
public JmxTransTimeSpreadExpiration(
long lowerBound,
long upperBound,
TimeUnit unit) {
if (lowerBound < 1) {
throw new IllegalArgumentException(
"The lower bound cannot be less than 1.");
}
if (upperBound <= lowerBound) {
throw new IllegalArgumentException(
"The upper bound must be greater than the lower bound.");
}
if (unit == null) {
throw new IllegalArgumentException("The TimeUnit cannot be null.");
}
this.lowerBoundMillis = unit.toMillis(lowerBound);
this.upperBoundMillis = unit.toMillis(upperBound);
this.unit = unit;
}
/**
* Returns `true`, with uniformly increasing probability, if the
* {@link stormpot.Poolable} represented by the given {@link SlotInfo} is
* older than the lower bound, eventually returning `true` with
* 100% certainty when the age of the Poolable is equal to or greater than
* the upper bound.
*
* The uniformity of the random expiration holds regardless of how often a
* Poolable is checked. That is to say, checking a Poolable more times within
* an interval of time, does _not_ increase its chances of being
* declared expired.
*/
@Override
public boolean hasExpired(SlotInfo<? extends T> info) {
long expirationAge = info.getStamp();
if (expirationAge == 0) {
long maxDelta = upperBoundMillis - lowerBoundMillis;
expirationAge = lowerBoundMillis + Math.abs(info.randomInt() % maxDelta);
info.setStamp(expirationAge);
}
long age = info.getAgeMillis();
return age >= expirationAge;
}
/**
* Produces a String representation of this TimeSpreadExpiration.
*/
@Override
public String toString() {
long lower = unit.convert(lowerBoundMillis, TimeUnit.MILLISECONDS);
long upper = unit.convert(upperBoundMillis, TimeUnit.MILLISECONDS);
return "TimeSpreadExpiration(" + lower + " to " + upper + " " + unit + ")";
}
}