package com.linkedin.parseq.batching;
import java.util.function.Function;
import org.HdrHistogram.Histogram;
import org.HdrHistogram.Recorder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BatchSizeMetric {
private static final Logger LOGGER = LoggerFactory.getLogger(BatchSizeMetric.class);
private static final int LOWEST_DISCERNIBLE_VALUE = 1;
private static final int HIGHEST_TRACKABLE_VALUE = 10_000;
private static final int NUMBER_OF_FIGNIFICANT_VALUE_DIGITS = 3;
private Recorder _recorder = null;
private Histogram _recycle;
/**
* Records a batch size.
* This method is thread safe.
* @param batchSize batch size
*/
public void record(int batchSize) {
recordSafeValue(narrow(batchSize));
}
private int narrow(int batchSize) {
if (batchSize < LOWEST_DISCERNIBLE_VALUE) {
LOGGER.warn("batch size lower than expected: {}, recording as: ", batchSize, LOWEST_DISCERNIBLE_VALUE);
return LOWEST_DISCERNIBLE_VALUE;
}
if (batchSize > HIGHEST_TRACKABLE_VALUE) {
LOGGER.warn("batch size greater than expected: {}, recording as: ", batchSize, HIGHEST_TRACKABLE_VALUE);
return HIGHEST_TRACKABLE_VALUE;
}
return batchSize;
}
private void initializeRecorder() {
if (_recorder == null) {
_recorder = new Recorder(LOWEST_DISCERNIBLE_VALUE, HIGHEST_TRACKABLE_VALUE, NUMBER_OF_FIGNIFICANT_VALUE_DIGITS);
}
}
private synchronized void recordSafeValue(int batchSize) {
initializeRecorder();
_recorder.recordValue(batchSize);
}
/**
* Allows consuming histogram and returning a result.
* Histogram passed to the consumer includes stable, consistent view
* of all values accumulated since last harvest.
* This method is thread safe.
* @param consumer consumer for a harvested histogram
* @param <T> return type of a passed in function
* @return a result of a passed in function
*/
public synchronized <T> T harvest(Function<Histogram, T> consumer) {
initializeRecorder();
_recycle = _recorder.getIntervalHistogram(_recycle);
return consumer.apply(_recycle);
}
}