Skip to content

Commit

Permalink
prepare release documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
vladimir-bukhtoyarov committed Nov 9, 2016
1 parent abad8ee commit f7945dc
Show file tree
Hide file tree
Showing 14 changed files with 141 additions and 56 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The library contains collection of advanced metrics which missed in the original
## Get Metrics-Core-HDR library

#### By direct link
[Download compiled jar, sources, javadocs](https://github.com/vladimir-bukhtoyarov/metrics-core-hdr/releases/tag/1.5.0)
[Download compiled jar, sources, javadocs](https://github.com/vladimir-bukhtoyarov/metrics-core-hdr/releases/tag/1.6.0)

#### You can build Metrics-Core-HDR from sources

Expand Down Expand Up @@ -44,7 +44,7 @@ Then include Metrics-Core-HDR as dependency to your `pom.xml`
<dependency>
<groupId>com.github.metrics-core-addons</groupId>
<artifactId>metrics-core-hdr</artifactId>
<version>1.5.0</version>
<version>1.6.0</version>
</dependency>
```

Expand Down
136 changes: 112 additions & 24 deletions src/main/java/com/github/metricscore/hdr/top/TopBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@
import java.time.Duration;
import java.util.concurrent.Executor;

/**
* The builder for {@link Top}.
*
* <p><br> Basic examples of usage:
* <pre> {@code
*
* Top top = Top.builder(3).resetAllPositionsOnSnapshot().build();
* MetricSet metricSet = new TopMetricSet("my-top", top, TimeUnit.MILLISECONDS, 5);
* registry.registerAll(metricSet);
* }</pre>
*
* <p>
* The responsibility of builder is only construction of {@link Top}, you should use {@link TopMetricSet} to integrate constructed {@link Top} into {@link com.codahale.metrics.MetricRegistry}
*
* @see Top
* @see TopMetricSet
*/
public class TopBuilder {

public static final int MAX_POSITION_COUNT = 1000;
Expand All @@ -34,60 +51,97 @@ public class TopBuilder {
public static final int MIN_LENGTH_OF_QUERY_DESCRIPTION = 10;
public static final int DEFAULT_MAX_LENGTH_OF_QUERY_DESCRIPTION = 1000;

public static final Duration DEFAULT_SLOW_QUERY_THRESHOLD = Duration.ZERO;
public static final Duration DEFAULT_LATENCY_THRESHOLD = Duration.ZERO;
public static final Duration DEFAULT_SNAPSHOT_CACHING_DURATION = Duration.ofSeconds(1);

private static final Executor DEFAULT_BACKGROUND_EXECUTOR = null;
private static final TopFactory DEFAULT_TOP_FACTORY = TopFactory.UNIFORM;

private int size;
private Duration slowQueryThreshold;
private Duration latencyThreshold;
private Duration snapshotCachingDuration;
private int maxDescriptionLengt;
private int maxDescriptionLength;
private Clock clock;
private Executor backgroundExecutor;
private TopFactory factory;

private TopBuilder(int size, Duration slowQueryThreshold, Duration snapshotCachingDuration, int maxDescriptionLengt, Clock clock, Executor backgroundExecutor, TopFactory factory) {
private TopBuilder(int size, Duration latencyThreshold, Duration snapshotCachingDuration, int maxDescriptionLength, Clock clock, Executor backgroundExecutor, TopFactory factory) {
this.size = size;
this.slowQueryThreshold = slowQueryThreshold;
this.latencyThreshold = latencyThreshold;
this.snapshotCachingDuration = snapshotCachingDuration;
this.maxDescriptionLengt = maxDescriptionLengt;
this.maxDescriptionLength = maxDescriptionLength;
this.clock = clock;
this.backgroundExecutor = backgroundExecutor;
this.factory = factory;
}

/**
* Constructs new {@link Top} instance
*
* @return new {@link Top} instance
*/
public Top build() {
Top top = factory.create(size, slowQueryThreshold, maxDescriptionLengt, clock);
Top top = factory.create(size, latencyThreshold, maxDescriptionLength, clock);
if (!snapshotCachingDuration.isZero()) {
top = new SnapshotCachingTop(top, snapshotCachingDuration.toMillis(), clock);
}
return top;
}

/**
* Creates new builder instance.
*
* @param size the count of positions for tops which will be constructed by this builder
* @return this builder instance
*/
public static TopBuilder newBuilder(int size) {
validateSize(size);
return new TopBuilder(size, DEFAULT_SLOW_QUERY_THRESHOLD, DEFAULT_SNAPSHOT_CACHING_DURATION, DEFAULT_MAX_LENGTH_OF_QUERY_DESCRIPTION, Clock.defaultClock(), DEFAULT_BACKGROUND_EXECUTOR, DEFAULT_TOP_FACTORY);
return new TopBuilder(size, DEFAULT_LATENCY_THRESHOLD, DEFAULT_SNAPSHOT_CACHING_DURATION, DEFAULT_MAX_LENGTH_OF_QUERY_DESCRIPTION, Clock.defaultClock(), DEFAULT_BACKGROUND_EXECUTOR, DEFAULT_TOP_FACTORY);
}

/**
* Configures the maximum count of positions for tops which will be constructed by this builder.
*
* @param size the maximum count of positions
* @return this builder instance
*/
public TopBuilder withPositionCount(int size) {
validateSize(size);
this.size = size;
return this;
}

public TopBuilder withSlowQueryThreshold(Duration slowQueryThreshold) {
if (slowQueryThreshold == null) {
throw new IllegalArgumentException("slowQueryThreshold should not be null");
/**
* Configures the latency threshold. The queries having latency which shorter than threshold, will not be tracked in the top.
* The default value is zero {@link #DEFAULT_LATENCY_THRESHOLD}, means that all queries can be recorded independent of its latency.
*
* Specify this parameter when you want not to track queries which fast,
* in other words when you want see nothing when all going well.
*
* @param latencyThreshold
* @return this builder instance
*/
public TopBuilder withLatencyThreshold(Duration latencyThreshold) {
if (latencyThreshold == null) {
throw new IllegalArgumentException("latencyThreshold should not be null");
}
if (slowQueryThreshold.isNegative()) {
throw new IllegalArgumentException("slowQueryThreshold should not be negative");
if (latencyThreshold.isNegative()) {
throw new IllegalArgumentException("latencyThreshold should not be negative");
}
this.slowQueryThreshold = slowQueryThreshold;
this.latencyThreshold = latencyThreshold;
return this;
}

/**
* Configures the duration for caching the results of invocation of {@link Top#getPositionsInDescendingOrder()}.
* Currently the caching is only one way to solve <a href="https://github.com/dropwizard/metrics/issues/1016">atomicity read problem</a>.
* The default value is one second {@link #DEFAULT_SNAPSHOT_CACHING_DURATION}.
* You can specify zero duration to discard caching at all, but theoretically,
* you should not disable cache until Dropwizard-Metrics reporting pipeline will be rewritten <a href="https://github.com/marshallpierce/metrics-thoughts">in scope of v-4-0</a>
*
* @param snapshotCachingDuration
* @return this builder instance
*/
public TopBuilder withSnapshotCachingDuration(Duration snapshotCachingDuration) {
if (snapshotCachingDuration == null) {
throw new IllegalArgumentException("snapshotCachingDuration should not be null");
Expand All @@ -99,17 +153,27 @@ public TopBuilder withSnapshotCachingDuration(Duration snapshotCachingDuration)
return this;
}

/**
*
* @param maxLengthOfQueryDescription
* @return
*/
public TopBuilder withMaxLengthOfQueryDescription(int maxLengthOfQueryDescription) {
if (maxLengthOfQueryDescription < MIN_LENGTH_OF_QUERY_DESCRIPTION) {
String msg = "The requested maxDescriptionLengt=" + maxLengthOfQueryDescription + " is wrong " +
"because of maxDescriptionLengt should be >=" + MIN_LENGTH_OF_QUERY_DESCRIPTION + "." +
String msg = "The requested maxDescriptionLength=" + maxLengthOfQueryDescription + " is wrong " +
"because of maxDescriptionLength should be >=" + MIN_LENGTH_OF_QUERY_DESCRIPTION + "." +
"How do you plan to distinguish one query from another with so short description?";
throw new IllegalArgumentException(msg);
}
this.maxDescriptionLengt = maxLengthOfQueryDescription;
this.maxDescriptionLength = maxLengthOfQueryDescription;
return this;
}

/**
*
* @param clock
* @return this builder instance
*/
public TopBuilder withClock(Clock clock) {
if (clock == null) {
throw new IllegalArgumentException("Clock should not be null");
Expand All @@ -118,6 +182,11 @@ public TopBuilder withClock(Clock clock) {
return this;
}

/**
*
* @param backgroundExecutor
* @return this builder instance
*/
public TopBuilder withBackgroundExecutor(Executor backgroundExecutor) {
if (backgroundExecutor == null) {
throw new IllegalArgumentException("Clock should not be null");
Expand All @@ -126,16 +195,29 @@ public TopBuilder withBackgroundExecutor(Executor backgroundExecutor) {
return this;
}

/**
*
* @return this builder instance
*/
public TopBuilder neverResetPositions() {
this.factory = TopFactory.UNIFORM;
return this;
}

/**
*
* @return this builder instance
*/
public TopBuilder resetAllPositionsOnSnapshot() {
this.factory = TopFactory.RESET_ON_SNAPSHOT;
return this;
}

/**
*
* @param intervalBetweenResetting
* @return this builder instance
*/
public TopBuilder resetAllPositionsPeriodically(Duration intervalBetweenResetting) {
if (intervalBetweenResetting == null) {
throw new IllegalArgumentException("intervalBetweenResetting should not be null");
Expand All @@ -152,6 +234,12 @@ public TopBuilder resetAllPositionsPeriodically(Duration intervalBetweenResettin
return this;
}

/**
*
* @param rollingWindow
* @param numberChunks
* @return this builder instance
*/
public TopBuilder resetAllPositionsPeriodicallyByChunks(Duration rollingWindow, int numberChunks) {
if (numberChunks > MAX_CHUNKS) {
throw new IllegalArgumentException("numberChunks should be <= " + MAX_CHUNKS);
Expand All @@ -178,19 +266,19 @@ public TopBuilder resetAllPositionsPeriodicallyByChunks(Duration rollingWindow,

private interface TopFactory {

Top create(int size, Duration slowQueryThreshold, int maxDescriptionLength, Clock clock);
Top create(int size, Duration latencyThreshold, int maxDescriptionLength, Clock clock);

TopFactory UNIFORM = new TopFactory() {
@Override
public Top create(int size, Duration slowQueryThreshold, int maxDescriptionLength, Clock clock) {
return new UniformTop(size, slowQueryThreshold.toNanos(), maxDescriptionLength);
public Top create(int size, Duration latencyThreshold, int maxDescriptionLength, Clock clock) {
return new UniformTop(size, latencyThreshold.toNanos(), maxDescriptionLength);
}
};

TopFactory RESET_ON_SNAPSHOT = new TopFactory() {
@Override
public Top create(int size, Duration slowQueryThreshold, int maxDescriptionLength, Clock clock) {
return new ResetOnSnapshotConcurrentTop(size, slowQueryThreshold.toNanos(), maxDescriptionLength);
public Top create(int size, Duration latencyThreshold, int maxDescriptionLength, Clock clock) {
return new ResetOnSnapshotConcurrentTop(size, latencyThreshold.toNanos(), maxDescriptionLength);
}
};

Expand All @@ -208,8 +296,8 @@ private static void validateSize(int size) {
private TopFactory resetByChunks(final long intervalBetweenResettingMillis, int numberOfHistoryChunks) {
return new TopFactory() {
@Override
public Top create(int size, Duration slowQueryThreshold, int maxDescriptionLength, Clock clock) {
return new ResetByChunksTop(size, slowQueryThreshold.toNanos(), maxDescriptionLength, intervalBetweenResettingMillis, numberOfHistoryChunks, clock, getExecutor());
public Top create(int size, Duration latencyThreshold, int maxDescriptionLength, Clock clock) {
return new ResetByChunksTop(size, latencyThreshold.toNanos(), maxDescriptionLength, intervalBetweenResettingMillis, numberOfHistoryChunks, clock, getExecutor());
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ public class ResetByChunksTop implements Top {
private final Phase[] phases;
private final AtomicReference<Phase> currentPhaseRef;

public ResetByChunksTop(int size, long slowQueryThresholdNanos, int maxDescriptionLength, long intervalBetweenResettingMillis, int numberHistoryChunks, Clock clock, Executor backgroundExecutor) {
public ResetByChunksTop(int size, long latencyThresholdNanos, int maxDescriptionLength, long intervalBetweenResettingMillis, int numberHistoryChunks, Clock clock, Executor backgroundExecutor) {
this.intervalBetweenResettingMillis = intervalBetweenResettingMillis;
this.clock = clock;
this.creationTimestamp = clock.currentTimeMillis();
this.backgroundExecutor = backgroundExecutor;

Supplier<TwoPhasePositionRecorder> recorderSupplier = () -> new TwoPhasePositionRecorder(size, slowQueryThresholdNanos, maxDescriptionLength);
Supplier<TwoPhasePositionRecorder> recorderSupplier = () -> new TwoPhasePositionRecorder(size, latencyThresholdNanos, maxDescriptionLength);
this.left = new Phase(recorderSupplier.get(), creationTimestamp + intervalBetweenResettingMillis);
this.right = new Phase(recorderSupplier.get(), Long.MAX_VALUE);
this.phases = new Phase[] {left, right};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ public class ResetOnSnapshotConcurrentTop implements Top {
private final TwoPhasePositionRecorder recorder;
private PositionRecorder intervalRecorder;

public ResetOnSnapshotConcurrentTop(int size, long slowQueryThresholdNanos, int maxDescriptionLength) {
this.recorder = new TwoPhasePositionRecorder(size, slowQueryThresholdNanos, maxDescriptionLength);
public ResetOnSnapshotConcurrentTop(int size, long latencyThresholdNanos, int maxDescriptionLength) {
this.recorder = new TwoPhasePositionRecorder(size, latencyThresholdNanos, maxDescriptionLength);
this.intervalRecorder = recorder.getIntervalRecorder();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ public class UniformTop implements Top {
private final PositionCollector uniformCollector;
private PositionRecorder intervalRecorder;

public UniformTop(int size, long slowQueryThresholdNanos, int maxDescriptionLength) {
this.phasedRecorder = new TwoPhasePositionRecorder(size, slowQueryThresholdNanos, maxDescriptionLength);
public UniformTop(int size, long latencyThresholdNanos, int maxDescriptionLength) {
this.phasedRecorder = new TwoPhasePositionRecorder(size, latencyThresholdNanos, maxDescriptionLength);
intervalRecorder = phasedRecorder.getIntervalRecorder();
this.uniformCollector = PositionCollector.createCollector(size);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ class MultiPositionRecorder extends PositionRecorder {
private final ConcurrentSkipListMap<PositionKey, Position> positions;
private final AtomicLong phaseSequence = new AtomicLong();

MultiPositionRecorder(int size, long slowQueryThresholdNanos, int maxDescriptionLength) {
super(size, slowQueryThresholdNanos, maxDescriptionLength);
MultiPositionRecorder(int size, long latencyThresholdNanos, int maxDescriptionLength) {
super(size, latencyThresholdNanos, maxDescriptionLength);
this.positions = new ConcurrentSkipListMap<>();

// init by fake values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,18 @@
public abstract class PositionRecorder {

protected final int size;
protected final long slowQueryThresholdNanos;
protected final long latencyThresholdNanos;
protected final int maxDescriptionLength;

protected PositionRecorder(int size, long slowQueryThresholdNanos, int maxDescriptionLength) {
this.slowQueryThresholdNanos = slowQueryThresholdNanos;
protected PositionRecorder(int size, long latencyThresholdNanos, int maxDescriptionLength) {
this.latencyThresholdNanos = latencyThresholdNanos;
this.size = size;
this.maxDescriptionLength = maxDescriptionLength;
}

public void update(long timestamp, long latencyTime, TimeUnit latencyUnit, Supplier<String> descriptionSupplier) {
long latencyNanos = latencyUnit.toNanos(latencyTime);
if (latencyNanos < slowQueryThresholdNanos) {
if (latencyNanos < latencyThresholdNanos) {
// the measure should be skipped because it is lesser then threshold
return;
}
Expand All @@ -52,16 +52,16 @@ public int getSize() {
return size;
}

public static PositionRecorder createRecorder(int size, long slowQueryThresholdNanos, int maxDescriptionLength) {
public static PositionRecorder createRecorder(int size, long latencyThresholdNanos, int maxDescriptionLength) {
if (size == 1) {
return new SinglePositionRecorder(slowQueryThresholdNanos, maxDescriptionLength);
return new SinglePositionRecorder(latencyThresholdNanos, maxDescriptionLength);
} else {
return new MultiPositionRecorder(size, slowQueryThresholdNanos, maxDescriptionLength);
return new MultiPositionRecorder(size, latencyThresholdNanos, maxDescriptionLength);
}
}

public PositionRecorder createEmptyCopy() {
return createRecorder(size, slowQueryThresholdNanos, maxDescriptionLength);
return createRecorder(size, latencyThresholdNanos, maxDescriptionLength);
}

protected boolean isNeedToAdd(long newTimestamp, long newLatency, Position currentMinimum) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ class SinglePositionRecorder extends PositionRecorder {

private final AtomicReference<Position> max;

SinglePositionRecorder(long slowQueryThresholdNanos, int maxDescriptionLength) {
super(1, slowQueryThresholdNanos, maxDescriptionLength);
SinglePositionRecorder(long latencyThresholdNanos, int maxDescriptionLength) {
super(1, latencyThresholdNanos, maxDescriptionLength);
this.max = new AtomicReference<>(null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public class TwoPhasePositionRecorder {
private volatile PositionRecorder active;
private PositionRecorder inactive;

public TwoPhasePositionRecorder(int size, long slowQueryThresholdNanos, int maxDescriptionLength) {
this.active = PositionRecorder.createRecorder(size, slowQueryThresholdNanos, maxDescriptionLength);
public TwoPhasePositionRecorder(int size, long latencyThresholdNanos, int maxDescriptionLength) {
this.active = PositionRecorder.createRecorder(size, latencyThresholdNanos, maxDescriptionLength);
this.inactive = null;
}

Expand Down
Loading

0 comments on commit f7945dc

Please sign in to comment.