common-utils/src/main/java/org/warp/commonutils/metrics/AtomicTimeIncrementalSample...

136 lines
3.8 KiB
Java

package org.warp.commonutils.metrics;
import java.util.Arrays;
public class AtomicTimeIncrementalSamples implements AtomicTimeIncrementalSamplesSnapshot {
protected final boolean isSnapshot;
protected long startTime;
protected final long[] samples;
protected final int sampleTime;
protected long currentSampleStartTime;
protected long totalEvents;
/**
*
* @param sampleTime in milliseconds
* @param samplesCount
*/
public AtomicTimeIncrementalSamples(int sampleTime, int samplesCount) {
this.samples = new long[samplesCount];
this.sampleTime = sampleTime;
startTime = -1;
if (samplesCount < 1) throw new IndexOutOfBoundsException();
if (sampleTime < 1) throw new IndexOutOfBoundsException();
this.isSnapshot = false;
}
public AtomicTimeIncrementalSamples(long startTime, long[] samples, int sampleTime, long currentSampleStartTime, long totalEvents, boolean isSnapshot) {
this.startTime = startTime;
this.samples = samples;
this.sampleTime = sampleTime;
this.currentSampleStartTime = currentSampleStartTime;
this.totalEvents = totalEvents;
this.isSnapshot = isSnapshot;
}
protected synchronized void updateSamples() {
checkStarted();
if (isSnapshot) {
return;
}
long currentTime = System.nanoTime() / 1000000L;
long timeDiff = currentTime - currentSampleStartTime;
long timeToShift = timeDiff - (timeDiff % sampleTime);
int shiftCount = (int) (timeToShift / sampleTime);
if (currentTime - (currentSampleStartTime + timeToShift) > sampleTime) {
throw new IndexOutOfBoundsException("Time sample bigger than " + sampleTime + "! It's " + (currentTime - (currentSampleStartTime + timeToShift)));
}
if (shiftCount > 0) {
shiftSamples(shiftCount);
currentSampleStartTime += timeToShift;
}
}
protected synchronized void checkStarted() {
if (startTime == -1) {
this.startTime = System.nanoTime() / 1000000L;
this.currentSampleStartTime = startTime;
}
}
protected synchronized void shiftSamples(int shiftCount) {
checkStarted();
if (samples.length - shiftCount > 0) {
System.arraycopy(samples, 0, samples, shiftCount, samples.length - shiftCount);
Arrays.fill(samples, 0, shiftCount, 0);
} else {
Arrays.fill(samples, 0);
}
}
public synchronized void increment(long count) {
updateSamples();
samples[0]+=count;
totalEvents+=count;
}
@Override
public synchronized double getAveragePerSecond(long timeRange) {
updateSamples();
double preciseTimeRange = timeRange;
// Fix if the time range is bigger than the collected data since start
if (currentSampleStartTime - preciseTimeRange < startTime) {
preciseTimeRange = currentSampleStartTime - startTime;
}
double samplesCount = Math.min(Math.max(preciseTimeRange / sampleTime, 1d), samples.length - 1);
if (samplesCount < 0) {
return 0;
}
double roundedTimeRange = samplesCount * sampleTime;
double value = 0;
for (int i = 1; i <= samplesCount; i++) {
value += samples[i];
}
return (value / roundedTimeRange) * 1000d;
}
@Override
public synchronized long getApproximateCount(long timeRange) {
updateSamples();
long samplesCount = Math.min(Math.max(timeRange / sampleTime, 1L), samples.length);
long value = 0;
for (int i = 0; i < samplesCount; i++) {
value += samples[i];
}
return value;
}
@Override
public synchronized long getTotalCount() {
updateSamples();
return totalEvents;
}
@Override
public synchronized double getTotalAveragePerSecond() {
updateSamples();
if (currentSampleStartTime == startTime) {
return 0;
}
return ((double) totalEvents) / (double) ((currentSampleStartTime - startTime) / 1000D);
}
public synchronized AtomicTimeIncrementalSamplesSnapshot snapshot() {
if (isSnapshot) {
return this;
}
return new AtomicTimeIncrementalSamples(startTime, Arrays.copyOf(this.samples, this.samples.length), sampleTime, currentSampleStartTime, totalEvents, true);
}
}