org.infinispan.extendedstats.percentiles.ReservoirSampler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of infinispan-extended-statistics Show documentation
Show all versions of infinispan-extended-statistics Show documentation
Infinispan Extended Statistics module
package org.infinispan.extendedstats.percentiles;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Keeps the sample for percentile calculations.
*
* Please check this for more details
*
* @author Roberto Palmieri
* @author Diego Didona
* @author Pedro Ruivo
* @since 6.0
*/
public class ReservoirSampler {
private static final int DEFAULT_NUM_SPOTS = 100;
private final AtomicInteger index;
private final Random random;
private double[] reservoir;
public ReservoirSampler() {
this(DEFAULT_NUM_SPOTS);
}
public ReservoirSampler(int numSpots) {
this.reservoir = createArray(numSpots);
this.index = new AtomicInteger(0);
random = new Random(System.nanoTime());
}
public synchronized final void insertSample(double sample) {
int i = index.getAndIncrement();
if (i < reservoir.length)
reservoir[i] = sample;
else {
int randGenerated = random.nextInt(i + 2);//should be nextInt(index+1) but nextInt is exclusive
if (randGenerated < reservoir.length) {
reservoir[randGenerated] = sample;
}
}
}
/**
* @param k the percentage of observations. Should be a value between 0 and 100 exclusively.
* @return the percentile value for the k% observations.
* @throws IllegalArgumentException if k is not between 0 and 100 exclusively.
*/
public synchronized final double getKPercentile(int k) throws IllegalArgumentException {
if (k < 0 || k > 100) {
throw new IllegalArgumentException(k + " should be between 0 and 100 exclusive");
}
double[] copy = createArray(reservoir.length);
System.arraycopy(this.reservoir, 0, copy, 0, reservoir.length);
Arrays.sort(copy);
return copy[this.getIndex(k)];
}
public synchronized final void reset() {
this.index.set(0);
this.reservoir = createArray(reservoir.length);
}
private int getIndex(int k) {
//I solve the proportion k:100=x:NUM_SAMPLE
//Every percentage is covered by NUM_SAMPLE / 100 buckets; I consider here only the first as representative
//of a percentage
return reservoir.length * (k - 1) / 100;
}
private double[] createArray(int size) {
return new double[size];
}
}