// ================================================================================================= // Copyright 2013 Twitter, Inc. // ------------------------------------------------------------------------------------------------- // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this work except in compliance with the License. // You may obtain a copy of the License in the LICENSE file, or at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ================================================================================================= package com.twitter.common.stats; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Supplier; import com.twitter.common.quantity.Amount; import com.twitter.common.quantity.Data; import com.twitter.common.quantity.Time; import com.twitter.common.util.Clock; /** * WindowedApproxHistogram is an implementation of WindowedHistogram with an * ApproximateHistogram as the underlying storing histogram. */ public class WindowedApproxHistogram extends WindowedHistogram<ApproximateHistogram> { @VisibleForTesting public static final int DEFAULT_SLICES = 3; @VisibleForTesting public static final Amount<Long, Time> DEFAULT_WINDOW = Amount.of(1L, Time.MINUTES); @VisibleForTesting public static final Amount<Long, Data> DEFAULT_MAX_MEMORY = Amount.of( (DEFAULT_SLICES + 1) * ApproximateHistogram.DEFAULT_MAX_MEMORY.as(Data.BYTES), Data.BYTES); /** * Create a {@code WindowedApproxHistogram } with a window duration of {@code window} and * decomposed in {@code slices} Histograms. Those Histograms will individually take less than * {@code maxMemory / (slices + 1)}. The clock will be used to find the correct index in the * ring buffer. * * @param window duration of the window * @param slices number of slices in the window * @param maxMemory maximum memory used by the whole histogram */ public WindowedApproxHistogram(Amount<Long, Time> window, final int slices, final Amount<Long, Data> maxMemory, Clock clock) { super(ApproximateHistogram.class, window, slices, new Supplier<ApproximateHistogram>() { private Amount<Long, Data> perHistogramMemory = Amount.of( maxMemory.as(Data.BYTES) / (slices + 1), Data.BYTES); @Override public ApproximateHistogram get() { return new ApproximateHistogram(perHistogramMemory); } }, new Function<ApproximateHistogram[], Histogram>() { @Override public Histogram apply(ApproximateHistogram[] histograms) { return ApproximateHistogram.merge(histograms); } }, clock); } /** * Create a {@code WindowedApproxHistogram } with a window duration of {@code window} and * decomposed in {@code slices} Histograms. Those Histograms will individually have a * precision of {@code precision / (slices + 1)}. The ticker will be used to measure elapsed * time in the WindowedHistogram. * * @param window duration of the window * @param slices number of slices in the window * @param precision precision of the whole histogram */ public WindowedApproxHistogram(Amount<Long, Time> window, final int slices, final Precision precision, Clock clock) { super(ApproximateHistogram.class, window, slices, new Supplier<ApproximateHistogram>() { private Precision perHistogramPrecision = new Precision( precision.getEpsilon(), precision.getN() / (slices + 1)); @Override public ApproximateHistogram get() { return new ApproximateHistogram(perHistogramPrecision); } }, new Function<ApproximateHistogram[], Histogram>() { @Override public Histogram apply(ApproximateHistogram[] histograms) { return ApproximateHistogram.merge(histograms); } }, clock); } /** * Equivalent to calling * {@link #WindowedApproxHistogram(Amount, int, Amount, Clock)} * with the System clock. */ public WindowedApproxHistogram(Amount<Long, Time> window, int slices, Amount<Long, Data> maxMemory) { this(window, slices, maxMemory, Clock.SYSTEM_CLOCK); } /** * Equivalent to calling * {@link #WindowedApproxHistogram(Amount, int, Amount)} * with default window and slices. */ public WindowedApproxHistogram(Amount<Long, Data> maxMemory) { this(DEFAULT_WINDOW, DEFAULT_SLICES, maxMemory); } /** * Equivalent to calling * {@link #WindowedApproxHistogram(Amount, int, Precision, Clock)} * with the System clock. */ public WindowedApproxHistogram(Amount<Long, Time> window, int slices, Precision precision) { this(window, slices, precision, Clock.SYSTEM_CLOCK); } /** * Equivalent to calling * {@link #WindowedApproxHistogram(Amount, int, Precision)} * with default window and slices. */ public WindowedApproxHistogram(Precision precision) { this(DEFAULT_WINDOW, DEFAULT_SLICES, precision); } /** * Equivalent to calling * {@link #WindowedApproxHistogram(Amount, int, Amount, Clock)} * with the default maxMemory parameter and System clock. */ public WindowedApproxHistogram(Amount<Long, Time> window, int slices) { this(window, slices, DEFAULT_MAX_MEMORY, Clock.SYSTEM_CLOCK); } /** * WindowedApproxHistogram constructor with default values. */ public WindowedApproxHistogram() { this(DEFAULT_WINDOW, DEFAULT_SLICES, DEFAULT_MAX_MEMORY, Clock.SYSTEM_CLOCK); } /** * WindowedApproxHistogram constructor with custom Clock (for testing purposes only). */ @VisibleForTesting public WindowedApproxHistogram(Clock clock) { this(DEFAULT_WINDOW, DEFAULT_SLICES, DEFAULT_MAX_MEMORY, clock); } }