org.HdrHistogram.SynchronizedHistogram Maven / Gradle / Ivy
/**
* Written by Gil Tene of Azul Systems, and released to the public domain,
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
*
* @author Gil Tene
*/
package org.HdrHistogram;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Locale;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
/**
* An integer values High Dynamic Range (HDR) Histogram that is synchronized as a whole
*
* A {@link SynchronizedHistogram} is a variant of {@link Histogram} that is
* synchronized as a whole, such that queries, copying, and addition operations are atomic with relation to
* modification on the {@link SynchronizedHistogram}, and such that external accessors (e.g. iterations on the
* histogram data) that synchronize on the {@link SynchronizedHistogram} instance can safely assume that no
* modifications to the histogram data occur within their synchronized block.
*
* It is important to note that synchronization can result in blocking recoding calls. If non-blocking recoding
* operations are required, consider using {@link ConcurrentHistogram}, {@link AtomicHistogram}, or (recommended)
* {@link Recorder} or {@link org.HdrHistogram.SingleWriterRecorder} which were intended for concurrent operations.
*
* See package description for {@link org.HdrHistogram} and {@link org.HdrHistogram.Histogram} for more details.
*/
public class SynchronizedHistogram extends Histogram {
/**
* Construct an auto-resizing SynchronizedHistogram with a lowest discernible value of 1 and an auto-adjusting
* highestTrackableValue. Can auto-resize up to track values up to (Long.MAX_VALUE / 2).
*
* @param numberOfSignificantValueDigits Specifies the precision to use. This is the number of significant
* decimal digits to which the histogram will maintain value resolution
* and separation. Must be a non-negative integer between 0 and 5.
*/
public SynchronizedHistogram(final int numberOfSignificantValueDigits) {
this(1, 2, numberOfSignificantValueDigits);
setAutoResize(true);
}
/**
* Construct a SynchronizedHistogram given the Highest value to be tracked and a number of significant decimal digits. The
* histogram will be constructed to implicitly track (distinguish from 0) values as low as 1.
*
* @param highestTrackableValue The highest value to be tracked by the histogram. Must be a positive
* integer that is {@literal >=} 2.
* @param numberOfSignificantValueDigits Specifies the precision to use. This is the number of significant
* decimal digits to which the histogram will maintain value resolution
* and separation. Must be a non-negative integer between 0 and 5.
*/
public SynchronizedHistogram(final long highestTrackableValue, final int numberOfSignificantValueDigits) {
this(1, highestTrackableValue, numberOfSignificantValueDigits);
}
/**
* Construct a SynchronizedHistogram given the Lowest and Highest values to be tracked and a number of significant
* decimal digits. Providing a lowestDiscernibleValue is useful is situations where the units used
* for the histogram's values are much smaller that the minimal accuracy required. E.g. when tracking
* time values stated in nanosecond units, where the minimal accuracy required is a microsecond, the
* proper value for lowestDiscernibleValue would be 1000.
*
* @param lowestDiscernibleValue The lowest value that can be tracked (distinguished from 0) by the histogram.
* Must be a positive integer that is {@literal >=} 1. May be internally rounded
* down to nearest power of 2.
* @param highestTrackableValue The highest value to be tracked by the histogram. Must be a positive
* integer that is {@literal >=} (2 * lowestDiscernibleValue).
* @param numberOfSignificantValueDigits Specifies the precision to use. This is the number of significant
* decimal digits to which the histogram will maintain value resolution
* and separation. Must be a non-negative integer between 0 and 5.
*/
public SynchronizedHistogram(final long lowestDiscernibleValue, final long highestTrackableValue, final int numberOfSignificantValueDigits) {
super(lowestDiscernibleValue, highestTrackableValue, numberOfSignificantValueDigits);
}
/**
* Construct a histogram with the same range settings as a given source histogram,
* duplicating the source's start/end timestamps (but NOT it's contents)
* @param source The source histogram to duplicate
*/
public SynchronizedHistogram(final AbstractHistogram source) {
super(source);
}
/**
* Construct a new histogram by decoding it from a ByteBuffer.
* @param buffer The buffer to decode from
* @param minBarForHighestTrackableValue Force highestTrackableValue to be set at least this high
* @return The newly constructed histogram
*/
public static SynchronizedHistogram decodeFromByteBuffer(final ByteBuffer buffer,
final long minBarForHighestTrackableValue) {
return decodeFromByteBuffer(buffer, SynchronizedHistogram.class, minBarForHighestTrackableValue);
}
/**
* Construct a new histogram by decoding it from a compressed form in a ByteBuffer.
* @param buffer The buffer to decode from
* @param minBarForHighestTrackableValue Force highestTrackableValue to be set at least this high
* @return The newly constructed histogram
* @throws DataFormatException on error parsing/decompressing the buffer
*/
public static SynchronizedHistogram decodeFromCompressedByteBuffer(final ByteBuffer buffer,
final long minBarForHighestTrackableValue) throws DataFormatException {
return decodeFromCompressedByteBuffer(buffer, SynchronizedHistogram.class, minBarForHighestTrackableValue);
}
@Override
public synchronized long getTotalCount() {
return super.getTotalCount();
}
@Override
public synchronized boolean isAutoResize() {
return super.isAutoResize();
}
@Override
public synchronized void setAutoResize(boolean autoResize) {
super.setAutoResize(autoResize);
}
@Override
public synchronized void recordValue(final long value) throws ArrayIndexOutOfBoundsException {
super.recordValue(value);
}
@Override
public synchronized void recordValueWithCount(final long value, final long count) throws ArrayIndexOutOfBoundsException {
super.recordValueWithCount(value, count);
}
@Override
public synchronized void recordValueWithExpectedInterval(final long value, final long expectedIntervalBetweenValueSamples)
throws ArrayIndexOutOfBoundsException {
super.recordValueWithExpectedInterval(value, expectedIntervalBetweenValueSamples);
}
/**
* @deprecated
*/
@Override
public synchronized void recordValue(final long value, final long expectedIntervalBetweenValueSamples)
throws ArrayIndexOutOfBoundsException {
super.recordValue(value, expectedIntervalBetweenValueSamples);
}
@Override
public synchronized void reset() {
super.reset();
}
@Override
public synchronized SynchronizedHistogram copy() {
SynchronizedHistogram toHistogram = new SynchronizedHistogram(this);
toHistogram.add(this);
return toHistogram;
}
@Override
public synchronized SynchronizedHistogram copyCorrectedForCoordinatedOmission(
final long expectedIntervalBetweenValueSamples) {
SynchronizedHistogram toHistogram = new SynchronizedHistogram(this);
toHistogram.addWhileCorrectingForCoordinatedOmission(this, expectedIntervalBetweenValueSamples);
return toHistogram;
}
@Override
public void copyInto(final AbstractHistogram targetHistogram) {
// Synchronize copyInto(). Avoid deadlocks by synchronizing in order of construction identity count.
if (identity < targetHistogram.identity) {
synchronized (this) {
synchronized (targetHistogram) {
super.copyInto(targetHistogram);
}
}
} else {
synchronized (targetHistogram) {
synchronized (this) {
super.copyInto(targetHistogram);
}
}
}
}
@Override
public void copyIntoCorrectedForCoordinatedOmission(final AbstractHistogram targetHistogram,
final long expectedIntervalBetweenValueSamples) {
// Synchronize copyIntoCorrectedForCoordinatedOmission(). Avoid deadlocks by synchronizing in order
// of construction identity count.
if (identity < targetHistogram.identity) {
synchronized (this) {
synchronized (targetHistogram) {
super.copyIntoCorrectedForCoordinatedOmission(targetHistogram, expectedIntervalBetweenValueSamples);
}
}
} else {
synchronized (targetHistogram) {
synchronized (this) {
super.copyIntoCorrectedForCoordinatedOmission(targetHistogram, expectedIntervalBetweenValueSamples);
}
}
}
}
@Override
public void add(final AbstractHistogram otherHistogram) {
// Synchronize add(). Avoid deadlocks by synchronizing in order of construction identity count.
if (identity < otherHistogram.identity) {
synchronized (this) {
synchronized (otherHistogram) {
super.add(otherHistogram);
}
}
} else {
synchronized (otherHistogram) {
synchronized (this) {
super.add(otherHistogram);
}
}
}
}
@Override
public void subtract(final AbstractHistogram otherHistogram)
throws ArrayIndexOutOfBoundsException, IllegalArgumentException {
// Synchronize subtract(). Avoid deadlocks by synchronizing in order of construction identity count.
if (identity < otherHistogram.identity) {
synchronized (this) {
synchronized (otherHistogram) {
super.subtract(otherHistogram);
}
}
} else {
synchronized (otherHistogram) {
synchronized (this) {
super.subtract(otherHistogram);
}
}
}
}
@Override
public void addWhileCorrectingForCoordinatedOmission(final AbstractHistogram fromHistogram,
final long expectedIntervalBetweenValueSamples) {
// Synchronize addWhileCorrectingForCoordinatedOmission(). Avoid deadlocks by synchronizing in
// order of construction identity count.
if (identity < fromHistogram.identity) {
synchronized (this) {
synchronized (fromHistogram) {
super.addWhileCorrectingForCoordinatedOmission(fromHistogram, expectedIntervalBetweenValueSamples);
}
}
} else {
synchronized (fromHistogram) {
synchronized (this) {
super.addWhileCorrectingForCoordinatedOmission(fromHistogram, expectedIntervalBetweenValueSamples);
}
}
}
}
@Override
public synchronized void shiftValuesLeft(final int numberOfBinaryOrdersOfMagnitude) {
super.shiftValuesLeft(numberOfBinaryOrdersOfMagnitude);
}
@Override
public synchronized void shiftValuesRight(final int numberOfBinaryOrdersOfMagnitude) {
super.shiftValuesRight(numberOfBinaryOrdersOfMagnitude);
}
@Override
public boolean equals(final Object other){
if ( this == other ) {
return true;
}
if (other instanceof AbstractHistogram) {
AbstractHistogram otherHistogram = (AbstractHistogram) other;
if (identity < otherHistogram.identity) {
synchronized (this) {
synchronized (otherHistogram) {
return super.equals(otherHistogram);
}
}
} else {
synchronized (otherHistogram) {
synchronized (this) {
return super.equals(otherHistogram);
}
}
}
} else {
synchronized (this) {
return super.equals(other);
}
}
}
@Override
public synchronized long getLowestDiscernibleValue() {
return super.getLowestDiscernibleValue();
}
@Override
public synchronized long getHighestTrackableValue() {
return super.getHighestTrackableValue();
}
@Override
public synchronized int getNumberOfSignificantValueDigits() {
return super.getNumberOfSignificantValueDigits();
}
@Override
public synchronized long sizeOfEquivalentValueRange(final long value) {
return super.sizeOfEquivalentValueRange(value);
}
@Override
public synchronized long lowestEquivalentValue(final long value) {
return super.lowestEquivalentValue(value);
}
@Override
public synchronized long highestEquivalentValue(final long value) {
return super.highestEquivalentValue(value);
}
@Override
public synchronized long medianEquivalentValue(final long value) {
return super.medianEquivalentValue(value);
}
@Override
public synchronized long nextNonEquivalentValue(final long value) {
return super.nextNonEquivalentValue(value);
}
@Override
public synchronized boolean valuesAreEquivalent(final long value1, final long value2) {
return super.valuesAreEquivalent(value1, value2);
}
@Override
public synchronized int getEstimatedFootprintInBytes() {
return super.getEstimatedFootprintInBytes();
}
@Override
public synchronized long getStartTimeStamp() {
return super.getStartTimeStamp();
}
@Override
public synchronized void setStartTimeStamp(final long timeStampMsec) {
super.setStartTimeStamp(timeStampMsec);
}
@Override
public synchronized long getEndTimeStamp() {
return super.getEndTimeStamp();
}
@Override
public synchronized void setEndTimeStamp(final long timeStampMsec) {
super.setEndTimeStamp(timeStampMsec);
}
@Override
public synchronized long getMinValue() {
return super.getMinValue();
}
@Override
public synchronized long getMaxValue() {
return super.getMaxValue();
}
@Override
public synchronized long getMinNonZeroValue() {
return super.getMinNonZeroValue();
}
@Override
public synchronized double getMaxValueAsDouble() {
return super.getMaxValueAsDouble();
}
@Override
public synchronized double getMean() {
return super.getMean();
}
@Override
public synchronized double getStdDeviation() {
return super.getStdDeviation();
}
@Override
public synchronized long getValueAtPercentile(final double percentile) {
return super.getValueAtPercentile(percentile);
}
@Override
public synchronized double getPercentileAtOrBelowValue(final long value) {
return super.getPercentileAtOrBelowValue(value);
}
@Override
public synchronized long getCountBetweenValues(final long lowValue, final long highValue) throws ArrayIndexOutOfBoundsException {
return super.getCountBetweenValues(lowValue, highValue);
}
@Override
public synchronized long getCountAtValue(final long value) throws ArrayIndexOutOfBoundsException {
return super.getCountAtValue(value);
}
@Override
public synchronized Percentiles percentiles(final int percentileTicksPerHalfDistance) {
return super.percentiles(percentileTicksPerHalfDistance);
}
@Override
public synchronized LinearBucketValues linearBucketValues(final long valueUnitsPerBucket) {
return super.linearBucketValues(valueUnitsPerBucket);
}
@Override
public synchronized LogarithmicBucketValues logarithmicBucketValues(final long valueUnitsInFirstBucket, final double logBase) {
return super.logarithmicBucketValues(valueUnitsInFirstBucket, logBase);
}
@Override
public synchronized RecordedValues recordedValues() {
return super.recordedValues();
}
@Override
public synchronized AllValues allValues() {
return super.allValues();
}
@Override
public synchronized void outputPercentileDistribution(final PrintStream printStream,
final Double outputValueUnitScalingRatio) {
super.outputPercentileDistribution(printStream, outputValueUnitScalingRatio);
}
@Override
public synchronized void outputPercentileDistribution(final PrintStream printStream,
final int percentileTicksPerHalfDistance,
final Double outputValueUnitScalingRatio) {
super.outputPercentileDistribution(printStream, percentileTicksPerHalfDistance, outputValueUnitScalingRatio);
}
@Override
public synchronized void outputPercentileDistribution(final PrintStream printStream,
final int percentileTicksPerHalfDistance,
final Double outputValueUnitScalingRatio,
final boolean useCsvFormat) {
super.outputPercentileDistribution(printStream, percentileTicksPerHalfDistance, outputValueUnitScalingRatio, useCsvFormat);
}
@Override
public synchronized int getNeededByteBufferCapacity() {
return super.getNeededByteBufferCapacity();
}
@Override
public synchronized int encodeIntoByteBuffer(final ByteBuffer buffer) {
return super.encodeIntoByteBuffer(buffer);
}
@Override
public synchronized int encodeIntoCompressedByteBuffer(
final ByteBuffer targetBuffer,
final int compressionLevel) {
return super.encodeIntoCompressedByteBuffer(targetBuffer, compressionLevel);
}
@Override
public synchronized int encodeIntoCompressedByteBuffer(final ByteBuffer targetBuffer) {
return super.encodeIntoCompressedByteBuffer(targetBuffer);
}
private void readObject(final ObjectInputStream o)
throws IOException, ClassNotFoundException {
o.defaultReadObject();
}
}