sonarqube fixes

This commit is contained in:
Jörg Prante 2016-11-01 16:31:22 +01:00
parent ec58c764d2
commit 1db95358c5
16 changed files with 193 additions and 152 deletions

View file

@ -1,7 +1,7 @@
ext { ext {
user = 'xbib' user = 'xbib'
name = 'metrics' name = 'metrics'
description = 'A stripped-down version of Coda Hale Metrics' description = 'A stripped-down and modified version of Coda Hale Metrics'
scmUrl = 'https://github.com/' + user + '/' + name scmUrl = 'https://github.com/' + user + '/' + name
scmConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git' scmConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git'
scmDeveloperConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git' scmDeveloperConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git'

View file

@ -1,20 +1,17 @@
package org.xbib.metrics; package org.xbib.metrics;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
/** /**
* An abstraction for how time passes. It is passed to {@link Sampler} to track timing. * An interface for how time passes. It is passed to {@link Sampler} to track timing.
*/ */
public abstract class Clock { public interface Clock {
/** /**
* The default clock to use. * The default clock to use.
* *
* @return the default {@link Clock} instance * @return the default {@link Clock} instance
* @see Clock.UserTimeClock * @see UserTimeClock
*/ */
public static Clock defaultClock() { static Clock defaultClock() {
return UserTimeClock.DEFAULT; return UserTimeClock.DEFAULT;
} }
@ -23,40 +20,13 @@ public abstract class Clock {
* *
* @return time tick in nanoseconds * @return time tick in nanoseconds
*/ */
public abstract long getTick(); long getTick();
/** /**
* Returns the current time in milliseconds. * Returns the current time in milliseconds.
* *
* @return time in milliseconds * @return time in milliseconds
*/ */
public long getTime() { long getTime();
return System.currentTimeMillis();
}
/**
* A clock implementation which returns the current time in epoch nanoseconds.
*/
public static class UserTimeClock extends Clock {
@Override
public long getTick() {
return System.nanoTime();
}
static final Clock DEFAULT = new UserTimeClock();
}
/**
* A clock implementation which returns the current thread's CPU time.
*/
public static class CpuTimeClock extends Clock {
private static final ThreadMXBean THREAD_MX_BEAN = ManagementFactory.getThreadMXBean();
@Override
public long getTick() {
return THREAD_MX_BEAN.getCurrentThreadCpuTime();
}
}
} }

View file

@ -0,0 +1,21 @@
package org.xbib.metrics;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
/**
* A clock implementation which returns the current thread's CPU time.
*/
class CpuTimeClock implements Clock {
private static final ThreadMXBean THREAD_MX_BEAN = ManagementFactory.getThreadMXBean();
@Override
public long getTick() {
return THREAD_MX_BEAN.getCurrentThreadCpuTime();
}
@Override
public long getTime() {
return System.currentTimeMillis();
}
}

View file

@ -15,7 +15,8 @@ public class ExpWeightedMovingAverage {
private static final double M5_ALPHA = 1 - Math.exp(-5 / 60.0 / 5); private static final double M5_ALPHA = 1 - Math.exp(-5 / 60.0 / 5);
private static final double M15_ALPHA = 1 - Math.exp(-5 / 60.0 / 15); private static final double M15_ALPHA = 1 - Math.exp(-5 / 60.0 / 15);
private final LongAdder uncounted = new LongAdder(); private final LongAdder uncounted = new LongAdder();
private final double alpha, interval; private final double alpha;
private final double interval;
private volatile boolean initialized = false; private volatile boolean initialized = false;
private volatile double rate = 0.0; private volatile double rate = 0.0;

View file

@ -72,10 +72,12 @@ public class ExponentiallyDecayingReservoir implements Reservoir {
this.nextScaleTime = new AtomicLong(clock.getTick() + RESCALE_THRESHOLD); this.nextScaleTime = new AtomicLong(clock.getTick() + RESCALE_THRESHOLD);
} }
@Override
public int size() { public int size() {
return (int) min(size, count.get()); return (int) min(size, count.get());
} }
@Override
public void update(long value) { public void update(long value) {
update(value, currentTimeInSeconds()); update(value, currentTimeInSeconds());
} }
@ -119,6 +121,7 @@ public class ExponentiallyDecayingReservoir implements Reservoir {
} }
} }
@Override
public Snapshot getSnapshot() { public Snapshot getSnapshot() {
lockForRegularUsage(); lockForRegularUsage();
try { try {

View file

@ -14,6 +14,7 @@ package org.xbib.metrics;
* *
* @param <T> the type of the metric's value * @param <T> the type of the metric's value
*/ */
@FunctionalInterface
public interface Gauge<T> extends Metric { public interface Gauge<T> extends Metric {
/** /**
* Returns the metric's current value. * Returns the metric's current value.

View file

@ -40,7 +40,7 @@ public class Histogram implements Metric, Sampling, Count {
@Override @Override
public void inc(String index, String type, String id) { public void inc(String index, String type, String id) {
// not used
} }
@Override @Override
@ -55,7 +55,7 @@ public class Histogram implements Metric, Sampling, Count {
@Override @Override
public void dec(String index, String type, String id) { public void dec(String index, String type, String id) {
// not used
} }
/** /**

View file

@ -46,12 +46,7 @@ public class Meter implements Metered {
public void spawn(long intervalSeconds) { public void spawn(long intervalSeconds) {
this.future = Executors.newScheduledThreadPool(1) this.future = Executors.newScheduledThreadPool(1)
.scheduleAtFixedRate(new Runnable() { .scheduleAtFixedRate(this::tickIfNecessary, intervalSeconds, intervalSeconds, TimeUnit.SECONDS);
@Override
public void run() {
tickIfNecessary();
}
}, intervalSeconds, intervalSeconds, TimeUnit.SECONDS);
} }
public void stop() { public void stop() {

View file

@ -3,16 +3,12 @@ package org.xbib.metrics;
/** /**
* A filter used to determine whether or not a metric should be reported, among other things. * A filter used to determine whether or not a metric should be reported, among other things.
*/ */
@FunctionalInterface
public interface MetricFilter { public interface MetricFilter {
/** /**
* Matches all metrics, regardless of type or name. * Matches all metrics, regardless of type or name.
*/ */
MetricFilter ALL = new MetricFilter() { MetricFilter ALL = (name, metric) -> true;
@Override
public boolean matches(MetricName name, Metric metric) {
return true;
}
};
/** /**
* Returns {@code true} if the metric matches the filter; {@code false} otherwise. * Returns {@code true} if the metric matches the filter; {@code false} otherwise.

View file

@ -41,7 +41,7 @@ public class MetricName implements Comparable<MetricName> {
**/ **/
public static MetricName join(MetricName... parts) { public static MetricName join(MetricName... parts) {
final StringBuilder nameBuilder = new StringBuilder(); final StringBuilder nameBuilder = new StringBuilder();
final Map<String, String> tags = new HashMap<String, String>(); final Map<String, String> tags = new HashMap<>();
boolean first = true; boolean first = true;
@ -92,16 +92,13 @@ public class MetricName implements Comparable<MetricName> {
if (name == null || name.isEmpty()) { if (name == null || name.isEmpty()) {
continue; continue;
} }
if (first) { if (first) {
first = false; first = false;
} else { } else {
builder.append(SEPARATOR); builder.append(SEPARATOR);
} }
builder.append(name); builder.append(name);
} }
return builder.toString(); return builder.toString();
} }
@ -109,7 +106,6 @@ public class MetricName implements Comparable<MetricName> {
if (tags == null || tags.isEmpty()) { if (tags == null || tags.isEmpty()) {
return EMPTY_TAGS; return EMPTY_TAGS;
} }
return Collections.unmodifiableMap(tags); return Collections.unmodifiableMap(tags);
} }
@ -132,7 +128,6 @@ public class MetricName implements Comparable<MetricName> {
*/ */
public MetricName resolve(String p) { public MetricName resolve(String p) {
final String next; final String next;
if (p != null && !p.isEmpty()) { if (p != null && !p.isEmpty()) {
if (key != null && !key.isEmpty()) { if (key != null && !key.isEmpty()) {
next = key + SEPARATOR + p; next = key + SEPARATOR + p;
@ -142,7 +137,6 @@ public class MetricName implements Comparable<MetricName> {
} else { } else {
next = this.key; next = this.key;
} }
return new MetricName(next, tags); return new MetricName(next, tags);
} }
@ -153,9 +147,9 @@ public class MetricName implements Comparable<MetricName> {
* @return A newly created metric name with the specified tags associated with it. * @return A newly created metric name with the specified tags associated with it.
*/ */
public MetricName tagged(Map<String, String> add) { public MetricName tagged(Map<String, String> add) {
final Map<String, String> tags = new HashMap<String, String>(add); final Map<String, String> map = new HashMap<>(add);
tags.putAll(this.tags); map.putAll(this.tags);
return new MetricName(key, tags); return new MetricName(key, map);
} }
/** /**
@ -171,17 +165,13 @@ public class MetricName implements Comparable<MetricName> {
if (pairs == null) { if (pairs == null) {
return this; return this;
} }
if (pairs.length % 2 != 0) { if (pairs.length % 2 != 0) {
throw new IllegalArgumentException("Argument count must be even"); throw new IllegalArgumentException("Argument count must be even");
} }
final Map<String, String> add = new HashMap<>();
final Map<String, String> add = new HashMap<String, String>();
for (int i = 0; i < pairs.length; i += 2) { for (int i = 0; i < pairs.length; i += 2) {
add.put(pairs[i], pairs[i + 1]); add.put(pairs[i], pairs[i + 1]);
} }
return tagged(add); return tagged(add);
} }
@ -189,9 +179,7 @@ public class MetricName implements Comparable<MetricName> {
public String toString() { public String toString() {
if (tags.isEmpty()) { if (tags.isEmpty()) {
return key; return key;
//return key + "{}";
} }
return key + tags; return key + tags;
} }
@ -209,17 +197,13 @@ public class MetricName implements Comparable<MetricName> {
if (this == obj) { if (this == obj) {
return true; return true;
} }
if (obj == null) { if (obj == null) {
return false; return false;
} }
if (getClass() != obj.getClass()) { if (getClass() != obj.getClass()) {
return false; return false;
} }
MetricName other = (MetricName) obj; MetricName other = (MetricName) obj;
if (key == null) { if (key == null) {
if (other.key != null) { if (other.key != null) {
return false; return false;
@ -227,23 +211,15 @@ public class MetricName implements Comparable<MetricName> {
} else if (!key.equals(other.key)) { } else if (!key.equals(other.key)) {
return false; return false;
} }
return tags.equals(other.tags); return tags.equals(other.tags);
} }
@Override @Override
public int compareTo(MetricName o) { public int compareTo(MetricName o) {
if (o == null) {
return -1;
}
int c = compareName(key, o.getKey()); int c = compareName(key, o.getKey());
if (c != 0) { if (c != 0) {
return c; return c;
} }
return compareTags(tags, o.getTags()); return compareTags(tags, o.getTags());
} }
@ -251,15 +227,12 @@ public class MetricName implements Comparable<MetricName> {
if (left == null && right == null) { if (left == null && right == null) {
return 0; return 0;
} }
if (left == null) { if (left == null) {
return 1; return 1;
} }
if (right == null) { if (right == null) {
return -1; return -1;
} }
return left.compareTo(right); return left.compareTo(right);
} }
@ -267,45 +240,35 @@ public class MetricName implements Comparable<MetricName> {
if (left == null && right == null) { if (left == null && right == null) {
return 0; return 0;
} }
if (left == null) { if (left == null) {
return 1; return 1;
} }
if (right == null) { if (right == null) {
return -1; return -1;
} }
final Iterable<String> keys = uniqueSortedKeys(left, right); final Iterable<String> keys = uniqueSortedKeys(left, right);
for (final String s : keys) {
for (final String key : keys) { final String a = left.get(s);
final String a = left.get(key); final String b = right.get(s);
final String b = right.get(key);
if (a == null && b == null) { if (a == null && b == null) {
continue; continue;
} }
if (a == null) { if (a == null) {
return -1; return -1;
} }
if (b == null) { if (b == null) {
return 1; return 1;
} }
int c = a.compareTo(b); int c = a.compareTo(b);
if (c != 0) { if (c != 0) {
return c; return c;
} }
} }
return 0; return 0;
} }
private Iterable<String> uniqueSortedKeys(Map<String, String> left, Map<String, String> right) { private Iterable<String> uniqueSortedKeys(Map<String, String> left, Map<String, String> right) {
final Set<String> set = new TreeSet<String>(left.keySet()); final Set<String> set = new TreeSet<>(left.keySet());
set.addAll(right.keySet()); set.addAll(right.keySet());
return set; return set;
} }

View file

@ -10,12 +10,15 @@ import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* A registry of metric instances. * A registry of metric instances.
*/ */
public class MetricRegistry implements MetricSet { public class MetricRegistry implements MetricSet {
private static final Logger logger = Logger.getLogger(MetricRegistry.class.getName());
private final ConcurrentMap<MetricName, Metric> metrics; private final ConcurrentMap<MetricName, Metric> metrics;
private final List<MetricRegistryListener> listeners; private final List<MetricRegistryListener> listeners;
@ -23,7 +26,7 @@ public class MetricRegistry implements MetricSet {
* Creates a new {@link MetricRegistry}. * Creates a new {@link MetricRegistry}.
*/ */
public MetricRegistry() { public MetricRegistry() {
this(new ConcurrentHashMap<MetricName, Metric>()); this(new ConcurrentHashMap<>());
} }
/** /**
@ -35,7 +38,7 @@ public class MetricRegistry implements MetricSet {
*/ */
protected MetricRegistry(ConcurrentMap<MetricName, Metric> metricsMap) { protected MetricRegistry(ConcurrentMap<MetricName, Metric> metricsMap) {
this.metrics = metricsMap; this.metrics = metricsMap;
this.listeners = new CopyOnWriteArrayList<MetricRegistryListener>(); this.listeners = new CopyOnWriteArrayList<>();
} }
/** /**
@ -68,7 +71,9 @@ public class MetricRegistry implements MetricSet {
} }
final String[] parts = new String[length + 1]; final String[] parts = new String[length + 1];
parts[0] = name; parts[0] = name;
if (names != null) {
System.arraycopy(names, 0, parts, 1, length); System.arraycopy(names, 0, parts, 1, length);
}
return MetricName.build(parts); return MetricName.build(parts);
} }
@ -80,7 +85,7 @@ public class MetricRegistry implements MetricSet {
* @see #register(MetricName, Metric) * @see #register(MetricName, Metric)
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends Metric> T register(String name, T metric) throws IllegalArgumentException { public <T extends Metric> T register(String name, T metric) {
return register(MetricName.build(name), metric); return register(MetricName.build(name), metric);
} }
@ -94,7 +99,7 @@ public class MetricRegistry implements MetricSet {
* @throws IllegalArgumentException if the name is already registered * @throws IllegalArgumentException if the name is already registered
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends Metric> T register(MetricName name, T metric) throws IllegalArgumentException { public <T extends Metric> T register(MetricName name, T metric) {
if (metric instanceof MetricSet) { if (metric instanceof MetricSet) {
registerAll(name, (MetricSet) metric); registerAll(name, (MetricSet) metric);
} else { } else {
@ -115,7 +120,7 @@ public class MetricRegistry implements MetricSet {
* @param metrics a set of metrics * @param metrics a set of metrics
* @throws IllegalArgumentException if any of the names are already registered * @throws IllegalArgumentException if any of the names are already registered
*/ */
public void registerAll(MetricSet metrics) throws IllegalArgumentException { public void registerAll(MetricSet metrics) {
registerAll(null, metrics); registerAll(null, metrics);
} }
@ -368,6 +373,7 @@ public class MetricRegistry implements MetricSet {
try { try {
return register(name, builder.newMetric()); return register(name, builder.newMetric());
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
logger.log(Level.WARNING, e.getMessage(), e);
final Metric added = metrics.get(name); final Metric added = metrics.get(name);
if (builder.isInstance(added)) { if (builder.isInstance(added)) {
return (T) added; return (T) added;
@ -379,7 +385,7 @@ public class MetricRegistry implements MetricSet {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T extends Metric> SortedMap<MetricName, T> getMetrics(Class<T> klass, MetricFilter filter) { private <T extends Metric> SortedMap<MetricName, T> getMetrics(Class<T> klass, MetricFilter filter) {
final TreeMap<MetricName, T> timers = new TreeMap<MetricName, T>(); final TreeMap<MetricName, T> timers = new TreeMap<>();
for (Map.Entry<MetricName, Metric> entry : metrics.entrySet()) { for (Map.Entry<MetricName, Metric> entry : metrics.entrySet()) {
if (klass.isInstance(entry.getValue()) && filter.matches(entry.getKey(), if (klass.isInstance(entry.getValue()) && filter.matches(entry.getKey(),
entry.getValue())) { entry.getValue())) {
@ -433,11 +439,8 @@ public class MetricRegistry implements MetricSet {
} }
} }
private void registerAll(MetricName prefix, MetricSet metrics) throws IllegalArgumentException { private void registerAll(MetricName prefixName, MetricSet metrics) {
if (prefix == null) { MetricName prefix = prefixName == null ? MetricName.EMPTY : prefixName;
prefix = MetricName.EMPTY;
}
for (Map.Entry<MetricName, Metric> entry : metrics.getMetrics().entrySet()) { for (Map.Entry<MetricName, Metric> entry : metrics.getMetrics().entrySet()) {
if (entry.getValue() instanceof MetricSet) { if (entry.getValue() instanceof MetricSet) {
registerAll(MetricName.join(prefix, entry.getKey()), (MetricSet) entry.getValue()); registerAll(MetricName.join(prefix, entry.getKey()), (MetricSet) entry.getValue());

View file

@ -7,6 +7,7 @@ import java.util.Map;
* *
* @see MetricRegistry#registerAll(MetricSet) * @see MetricRegistry#registerAll(MetricSet)
*/ */
@FunctionalInterface
public interface MetricSet extends Metric { public interface MetricSet extends Metric {
/** /**
* A map of metric names to metrics. * A map of metric names to metrics.

View file

@ -3,6 +3,7 @@ package org.xbib.metrics;
/** /**
* An object which samples values. * An object which samples values.
*/ */
@FunctionalInterface
public interface Sampling { public interface Sampling {
/** /**
* Returns a snapshot of the values. * Returns a snapshot of the values.

View file

@ -3,9 +3,9 @@ package org.xbib.metrics;
import java.io.OutputStream; import java.io.OutputStream;
/** /**
* A statistical snapshot of a {@link Snapshot}. * A {@link Snapshot}.
*/ */
public abstract class Snapshot { public interface Snapshot {
/** /**
* Returns the value at the given quantile. * Returns the value at the given quantile.
@ -13,109 +13,97 @@ public abstract class Snapshot {
* @param quantile a given quantile, in {@code [0..1]} * @param quantile a given quantile, in {@code [0..1]}
* @return the value in the distribution at {@code quantile} * @return the value in the distribution at {@code quantile}
*/ */
public abstract double getValue(double quantile); double getValue(double quantile);
/** /**
* Returns the entire set of values in the snapshot. * Returns the entire set of values in the snapshot.
* *
* @return the entire set of values * @return the entire set of values
*/ */
public abstract long[] getValues(); long[] getValues();
/** /**
* Returns the number of values in the snapshot. * Returns the number of values in the snapshot.
* *
* @return the number of values * @return the number of values
*/ */
public abstract int size(); int size();
/** /**
* Returns the median value in the distribution. * Returns the median value in the distribution.
* *
* @return the median value * @return the median value
*/ */
public double getMedian() { double getMedian();
return getValue(0.5);
}
/** /**
* Returns the value at the 75th percentile in the distribution. * Returns the value at the 75th percentile in the distribution.
* *
* @return the value at the 75th percentile * @return the value at the 75th percentile
*/ */
public double get75thPercentile() { double get75thPercentile();
return getValue(0.75);
}
/** /**
* Returns the value at the 95th percentile in the distribution. * Returns the value at the 95th percentile in the distribution.
* *
* @return the value at the 95th percentile * @return the value at the 95th percentile
*/ */
public double get95thPercentile() { double get95thPercentile();
return getValue(0.95);
}
/** /**
* Returns the value at the 98th percentile in the distribution. * Returns the value at the 98th percentile in the distribution.
* *
* @return the value at the 98th percentile * @return the value at the 98th percentile
*/ */
public double get98thPercentile() { double get98thPercentile();
return getValue(0.98);
}
/** /**
* Returns the value at the 99th percentile in the distribution. * Returns the value at the 99th percentile in the distribution.
* *
* @return the value at the 99th percentile * @return the value at the 99th percentile
*/ */
public double get99thPercentile() { double get99thPercentile();
return getValue(0.99);
}
/** /**
* Returns the value at the 99.9th percentile in the distribution. * Returns the value at the 99.9th percentile in the distribution.
* *
* @return the value at the 99.9th percentile * @return the value at the 99.9th percentile
*/ */
public double get999thPercentile() { double get999thPercentile();
return getValue(0.999);
}
/** /**
* Returns the highest value in the snapshot. * Returns the highest value in the snapshot.
* *
* @return the highest value * @return the highest value
*/ */
public abstract long getMax(); long getMax();
/** /**
* Returns the arithmetic mean of the values in the snapshot. * Returns the arithmetic mean of the values in the snapshot.
* *
* @return the arithmetic mean * @return the arithmetic mean
*/ */
public abstract double getMean(); double getMean();
/** /**
* Returns the lowest value in the snapshot. * Returns the lowest value in the snapshot.
* *
* @return the lowest value * @return the lowest value
*/ */
public abstract long getMin(); long getMin();
/** /**
* Returns the standard deviation of the values in the snapshot. * Returns the standard deviation of the values in the snapshot.
* *
* @return the standard value * @return the standard value
*/ */
public abstract double getStdDev(); double getStdDev();
/** /**
* Writes the values of the snapshot to the given stream. * Writes the values of the snapshot to the given stream.
* *
* @param output an output stream * @param output an output stream
*/ */
public abstract void dump(OutputStream output); void dump(OutputStream output);
} }

View file

@ -0,0 +1,20 @@
package org.xbib.metrics;
/**
* A clock implementation which returns the current time in epoch nanoseconds.
*/
class UserTimeClock implements Clock {
static final Clock DEFAULT = new UserTimeClock();
@Override
public long getTick() {
return System.nanoTime();
}
@Override
public long getTime() {
return System.currentTimeMillis();
}
}

View file

@ -6,12 +6,11 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Comparator;
/** /**
* A statistical snapshot of a {@link WeightedSnapshot}. * A statistical snapshot of a {@link WeightedSnapshot}.
*/ */
public class WeightedSnapshot extends Snapshot { public class WeightedSnapshot implements Snapshot {
private final long[] values; private final long[] values;
private final double[] normWeights; private final double[] normWeights;
@ -25,9 +24,7 @@ public class WeightedSnapshot extends Snapshot {
public WeightedSnapshot(Collection<WeightedSample> values) { public WeightedSnapshot(Collection<WeightedSample> values) {
final WeightedSample[] copy = values.toArray(new WeightedSample[]{}); final WeightedSample[] copy = values.toArray(new WeightedSample[]{});
Arrays.sort(copy, new Comparator<WeightedSample>() { Arrays.sort(copy, (o1, o2) -> {
@Override
public int compare(WeightedSample o1, WeightedSample o2) {
if (o1.value > o2.value) { if (o1.value > o2.value) {
return 1; return 1;
} }
@ -35,21 +32,20 @@ public class WeightedSnapshot extends Snapshot {
return -1; return -1;
} }
return 0; return 0;
}
}); });
this.values = new long[copy.length]; this.values = new long[copy.length];
this.normWeights = new double[copy.length]; this.normWeights = new double[copy.length];
this.quantiles = new double[copy.length]; this.quantiles = new double[copy.length];
double sumWeight = 0; double sumWeight = 0.0f;
for (WeightedSample sample : copy) { for (WeightedSample sample : copy) {
sumWeight += sample.weight; sumWeight += sample.weight;
} }
for (int i = 0; i < copy.length; i++) { for (int i = 0; i < copy.length; i++) {
this.values[i] = copy[i].value; this.values[i] = copy[i].value;
this.normWeights[i] = copy[i].weight / sumWeight; this.normWeights[i] = safeDivide(copy[i].weight, sumWeight);
} }
for (int i = 1; i < copy.length; i++) { for (int i = 1; i < copy.length; i++) {
@ -57,6 +53,88 @@ public class WeightedSnapshot extends Snapshot {
} }
} }
private static double safeDivide(double dividend, double divisor) {
if (Double.compare(divisor, Double.NaN) == 0) {
return Double.NaN;
}
if (Double.compare(dividend, Double.NaN) == 0) {
return Double.NaN;
}
if (Double.compare(divisor, 0.0) == 0) {
if (Double.compare(dividend, 0.0) == -1) {
return Double.NEGATIVE_INFINITY;
}
return Double.POSITIVE_INFINITY;
}
if (Double.compare(divisor, -0.0) == 0) {
if (Double.compare(dividend, -0.0) == 1) {
return Double.NEGATIVE_INFINITY;
}
return Double.POSITIVE_INFINITY;
}
return dividend / divisor;
}
/**
* Returns the median value in the distribution.
*
* @return the median value
*/
@Override
public double getMedian() {
return getValue(0.5);
}
/**
* Returns the value at the 75th percentile in the distribution.
*
* @return the value at the 75th percentile
*/
@Override
public double get75thPercentile() {
return getValue(0.75);
}
/**
* Returns the value at the 95th percentile in the distribution.
*
* @return the value at the 95th percentile
*/
@Override
public double get95thPercentile() {
return getValue(0.95);
}
/**
* Returns the value at the 98th percentile in the distribution.
*
* @return the value at the 98th percentile
*/
@Override
public double get98thPercentile() {
return getValue(0.98);
}
/**
* Returns the value at the 99th percentile in the distribution.
*
* @return the value at the 99th percentile
*/
@Override
public double get99thPercentile() {
return getValue(0.99);
}
/**
* Returns the value at the 99.9th percentile in the distribution.
*
* @return the value at the 99.9th percentile
*/
@Override
public double get999thPercentile() {
return getValue(0.999);
}
/** /**
* Returns the value at the given quantile. * Returns the value at the given quantile.
* *