package io.dropwizard.metrics; import org.HdrHistogram.Histogram; import org.HdrHistogram.Recorder; import javax.annotation.Nonnull; import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; /** * A Reservoir that resets its internal state every time a snapshot is taken. This is useful if you're using snapshots * as a means of defining the window in which you want to calculate, say, the 99.9th percentile. */ @ThreadSafe public final class HdrHistogramResetOnSnapshotReservoir implements Reservoir { private final Recorder recorder; @GuardedBy("this") @Nonnull private Histogram intervalHistogram; /** * Create a reservoir with a default recorder. This recorder should be suitable for most usage. */ public HdrHistogramResetOnSnapshotReservoir() { this(new Recorder(2)); } /** * Create a reservoir with a user-specified recorder. * * @param recorder Recorder to use */ public HdrHistogramResetOnSnapshotReservoir(Recorder recorder) { this.recorder = recorder; /* * Start by flipping the recorder's interval histogram. * - it starts our counting at zero. Arguably this might be a bad thing if you wanted to feed in * a recorder that already had some measurements? But that seems crazy. * - intervalHistogram can be nonnull. */ intervalHistogram = recorder.getIntervalHistogram(); } @Override public int size() { // This appears to be infrequently called, so not keeping a separate counter just for this. return getSnapshot().size(); } @Override public void update(long value) { recorder.recordValue(value); } /** * @return the data since the last snapshot was taken */ @Override public Snapshot getSnapshot() { return new HistogramSnapshot(getDataSinceLastSnapshotAndReset()); } /** * @return a copy of the accumulated state since the reservoir last had a snapshot */ @Nonnull private synchronized Histogram getDataSinceLastSnapshotAndReset() { intervalHistogram = recorder.getIntervalHistogram(intervalHistogram); return intervalHistogram.copy(); } }