Skip to content

Commit 772cff7

Browse files
committed
Review fixes
1 parent 4348004 commit 772cff7

File tree

6 files changed

+100
-49
lines changed

6 files changed

+100
-49
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright Elasticsearch B.V., and/or licensed to Elasticsearch B.V.
3+
* under one or more license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*
19+
* This file is based on a modification of https://github.com/open-telemetry/opentelemetry-java which is licensed under the Apache 2.0 License.
20+
*/
21+
22+
package org.elasticsearch.exponentialhistogram;
23+
24+
/**
25+
* Basic implementation for {@link ExponentialHistogram} with common functionality.
26+
*/
27+
public abstract class AbstractExponentialHistogram implements ExponentialHistogram {
28+
29+
@Override
30+
public long valueCount() {
31+
return zeroBucket().count() + negativeBuckets().valueCount() + positiveBuckets().valueCount();
32+
}
33+
34+
@Override
35+
public int hashCode() {
36+
return ExponentialHistogram.hashCode(this);
37+
}
38+
39+
@Override
40+
public boolean equals(Object obj) {
41+
if (this == obj) {
42+
return true;
43+
}
44+
if (obj instanceof ExponentialHistogram) {
45+
return ExponentialHistogram.equals(this, (ExponentialHistogram) obj);
46+
}
47+
return false;
48+
}
49+
}

libs/exponential-histogram/src/main/java/org/elasticsearch/exponentialhistogram/EmptyExponentialHistogram.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
import java.util.OptionalLong;
2525

26-
class EmptyExponentialHistogram extends ReleasableExponentialHistogram {
26+
class EmptyExponentialHistogram extends AbstractExponentialHistogram implements ReleasableExponentialHistogram {
2727

2828
static final EmptyExponentialHistogram INSTANCE = new EmptyExponentialHistogram();
2929

libs/exponential-histogram/src/main/java/org/elasticsearch/exponentialhistogram/ExponentialHistogram.java

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828
import java.util.OptionalLong;
2929

3030
/**
31-
* Base class for implementations of exponential histograms adhering to the
31+
* Interface for implementations of exponential histograms adhering to the
3232
* <a href="https://opentelemetry.io/docs/specs/otel/metrics/data-model/#exponentialhistogram">OpenTelemetry definition</a>.
33-
* This class supports sparse implementations, allowing iteration over buckets without requiring direct index access.<br>
33+
* This interface supports sparse implementations, allowing iteration over buckets without requiring direct index access.<br>
3434
* The most important properties are:
3535
* <ul>
3636
* <li>The histogram has a scale parameter, which defines the accuracy. A higher scale implies a higher accuracy.
@@ -45,7 +45,7 @@
4545
* Additionally, all algorithms assume that samples within a bucket are located at a single point: the point of least relative error
4646
* (see {@link ExponentialScaleUtils#getPointOfLeastRelativeError(long, int)}).
4747
*/
48-
public abstract class ExponentialHistogram implements Accountable {
48+
public interface ExponentialHistogram extends Accountable {
4949

5050
// TODO(b/128622): support min/max storage and merging.
5151
// TODO(b/128622): Add special positive and negative infinity buckets
@@ -56,42 +56,42 @@ public abstract class ExponentialHistogram implements Accountable {
5656
// Theoretically, a MAX_SCALE of 51 would work and would still cover the entire range of double values.
5757
// For that to work, the math for converting from double to indices and back would need to be reworked.
5858
// One option would be to use "Quadruple": https://github.com/m-vokhm/Quadruple
59-
public static final int MAX_SCALE = 38;
59+
int MAX_SCALE = 38;
6060

6161
// At this scale, all double values fall into a single bucket.
62-
public static final int MIN_SCALE = -11;
62+
int MIN_SCALE = -11;
6363

6464
// Only use 62 bits (plus the sign bit) at max to allow computing the difference between the smallest and largest index without causing
6565
// an overflow.
6666
// The extra bit also provides room for compact storage tricks.
67-
public static final int MAX_INDEX_BITS = 62;
68-
public static final long MAX_INDEX = (1L << MAX_INDEX_BITS) - 1;
69-
public static final long MIN_INDEX = -MAX_INDEX;
67+
int MAX_INDEX_BITS = 62;
68+
long MAX_INDEX = (1L << MAX_INDEX_BITS) - 1;
69+
long MIN_INDEX = -MAX_INDEX;
7070

7171
/**
7272
* The scale of the histogram. Higher scales result in higher accuracy but potentially more buckets.
7373
* Must be less than or equal to {@link #MAX_SCALE} and greater than or equal to {@link #MIN_SCALE}.
7474
*
7575
* @return the scale of the histogram
7676
*/
77-
public abstract int scale();
77+
int scale();
7878

7979
/**
8080
* @return the {@link ZeroBucket} representing the number of zero (or close-to-zero) values and its threshold
8181
*/
82-
public abstract ZeroBucket zeroBucket();
82+
ZeroBucket zeroBucket();
8383

8484
/**
8585
* @return a {@link Buckets} instance for the populated buckets covering the positive value range of this histogram.
8686
* The {@link BucketIterator#scale()} of iterators obtained via {@link Buckets#iterator()} must be the same as {@link #scale()}.
8787
*/
88-
public abstract Buckets positiveBuckets();
88+
Buckets positiveBuckets();
8989

9090
/**
9191
* @return a {@link Buckets} instance for the populated buckets covering the negative value range of this histogram.
9292
* The {@link BucketIterator#scale()} of iterators obtained via {@link Buckets#iterator()} must be the same as {@link #scale()}.
9393
*/
94-
public abstract Buckets negativeBuckets();
94+
Buckets negativeBuckets();
9595

9696
/**
9797
* Returns the sum of all values represented by this histogram.
@@ -100,22 +100,20 @@ public abstract class ExponentialHistogram implements Accountable {
100100
*
101101
* @return the sum, guaranteed to be zero for empty histograms
102102
*/
103-
public abstract double sum();
103+
double sum();
104104

105105
/**
106106
* Returns the number of values represented by this histogram.
107107
* In other words, this is the sum of the counts of all buckets including the zero bucket.
108108
*
109109
* @return the value count, guaranteed to be zero for empty histograms
110110
*/
111-
public long valueCount() {
112-
return zeroBucket().count() + positiveBuckets().valueCount() + negativeBuckets().valueCount();
113-
}
111+
long valueCount();
114112

115113
/**
116114
* Represents a bucket range of an {@link ExponentialHistogram}, either the positive or the negative range.
117115
*/
118-
public interface Buckets {
116+
interface Buckets {
119117

120118
/**
121119
* @return a {@link BucketIterator} for the populated buckets of this bucket range.
@@ -135,23 +133,22 @@ public interface Buckets {
135133

136134
}
137135

138-
@Override
139-
public boolean equals(Object other) {
140-
if (this == other) return true;
141-
if (other == null) return false;
142-
143-
if ((other instanceof ExponentialHistogram) == false) {
144-
return false;
145-
}
146-
ExponentialHistogram that = (ExponentialHistogram) other;
147-
148-
if (scale() != that.scale()) return false;
149-
if (sum() != that.sum()) return false;
150-
if (zeroBucket().equals(that.zeroBucket()) == false) return false;
151-
if (bucketIteratorsEqual(negativeBuckets().iterator(), that.negativeBuckets().iterator()) == false) return false;
152-
if (bucketIteratorsEqual(positiveBuckets().iterator(), that.positiveBuckets().iterator()) == false) return false;
153-
154-
return true;
136+
/**
137+
* Value-based equality for exponential histograms.
138+
* @param a the first histogram (can be null)
139+
* @param b the second histogram (can be null)
140+
* @return true, if both histograms are equal
141+
*/
142+
static boolean equals(ExponentialHistogram a, ExponentialHistogram b) {
143+
if (a == b) return true;
144+
if (a == null) return false;
145+
if (b == null) return false;
146+
147+
return a.scale() == b.scale()
148+
&& a.sum() == b.sum()
149+
&& a.zeroBucket().equals(b.zeroBucket())
150+
&& bucketIteratorsEqual(a.negativeBuckets().iterator(), b.negativeBuckets().iterator())
151+
&& bucketIteratorsEqual(a.positiveBuckets().iterator(), b.positiveBuckets().iterator());
155152
}
156153

157154
private static boolean bucketIteratorsEqual(BucketIterator a, BucketIterator b) {
@@ -168,19 +165,23 @@ private static boolean bucketIteratorsEqual(BucketIterator a, BucketIterator b)
168165
return a.hasNext() == b.hasNext();
169166
}
170167

171-
@Override
172-
public int hashCode() {
173-
int hash = scale();
174-
hash = 31 * hash + Double.hashCode(sum());
175-
hash = 31 * hash + zeroBucket().hashCode();
176-
hash = 31 * hash + Long.hashCode(valueCount());
168+
/**
169+
* Default hash code implementation to be used with {@link #equals(ExponentialHistogram, ExponentialHistogram)}.
170+
* @param histogram the histogram to hash
171+
* @return the hash code
172+
*/
173+
static int hashCode(ExponentialHistogram histogram) {
174+
int hash = histogram.scale();
175+
hash = 31 * hash + Double.hashCode(histogram.sum());
176+
hash = 31 * hash + histogram.zeroBucket().hashCode();
177+
hash = 31 * hash + Long.hashCode(histogram.valueCount());
177178
// we intentionally don't include the hash of the buckets here, because that is likely expensive to compute
178179
// instead, we assume that the value count and sum are a good enough approximation in most cases to minimize collisions
179180
// the value count is typically available as a cached value and doesn't involve iterating over all buckets
180181
return hash;
181182
}
182183

183-
public static ExponentialHistogram empty() {
184+
static ExponentialHistogram empty() {
184185
return EmptyExponentialHistogram.INSTANCE;
185186
}
186187

@@ -194,7 +195,7 @@ public static ExponentialHistogram empty() {
194195
* @param values the values to be added to the histogram
195196
* @return a new {@link ReleasableExponentialHistogram}
196197
*/
197-
public static ReleasableExponentialHistogram create(int maxBucketCount, ExponentialHistogramCircuitBreaker breaker, double... values) {
198+
static ReleasableExponentialHistogram create(int maxBucketCount, ExponentialHistogramCircuitBreaker breaker, double... values) {
198199
try (ExponentialHistogramGenerator generator = ExponentialHistogramGenerator.create(maxBucketCount, breaker)) {
199200
for (double val : values) {
200201
generator.add(val);
@@ -211,7 +212,7 @@ public static ReleasableExponentialHistogram create(int maxBucketCount, Exponent
211212
* @param histograms the histograms to merge
212213
* @return the merged histogram
213214
*/
214-
public static ReleasableExponentialHistogram merge(
215+
static ReleasableExponentialHistogram merge(
215216
int maxBucketCount,
216217
ExponentialHistogramCircuitBreaker breaker,
217218
Iterator<ExponentialHistogram> histograms
@@ -232,7 +233,7 @@ public static ReleasableExponentialHistogram merge(
232233
* @param histograms the histograms to merge
233234
* @return the merged histogram
234235
*/
235-
public static ReleasableExponentialHistogram merge(
236+
static ReleasableExponentialHistogram merge(
236237
int maxBucketCount,
237238
ExponentialHistogramCircuitBreaker breaker,
238239
ExponentialHistogram... histograms

libs/exponential-histogram/src/main/java/org/elasticsearch/exponentialhistogram/FixedCapacityExponentialHistogram.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
* Consumers must ensure that if the histogram is mutated, all previously acquired {@link BucketIterator}
3232
* instances are no longer used.
3333
*/
34-
final class FixedCapacityExponentialHistogram extends ReleasableExponentialHistogram {
34+
final class FixedCapacityExponentialHistogram extends AbstractExponentialHistogram implements ReleasableExponentialHistogram {
3535

3636
static final long BASE_SIZE = RamUsageEstimator.shallowSizeOfInstance(FixedCapacityExponentialHistogram.class) + ZeroBucket.SHALLOW_SIZE
3737
+ 2 * Buckets.SHALLOW_SIZE;

libs/exponential-histogram/src/main/java/org/elasticsearch/exponentialhistogram/ReleasableExponentialHistogram.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626
/**
2727
* A histogram which participates in the {@link ExponentialHistogramCircuitBreaker} and therefore requires proper releasing.
2828
*/
29-
public abstract class ReleasableExponentialHistogram extends ExponentialHistogram implements Releasable {
29+
public interface ReleasableExponentialHistogram extends ExponentialHistogram, Releasable {
3030

3131
/**
3232
* @return an empty singleton, which does not allocate any memory and therefore {@link #close()} is a no-op.
3333
*/
34-
public static ReleasableExponentialHistogram empty() {
34+
static ReleasableExponentialHistogram empty() {
3535
return EmptyExponentialHistogram.INSTANCE;
3636
}
3737
}

x-pack/plugin/mapper-exponential-histogram/src/main/java/org/elasticsearch/xpack/exponentialhistogram/CompressedExponentialHistogram.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.apache.lucene.util.BytesRef;
1111
import org.apache.lucene.util.RamUsageEstimator;
1212
import org.elasticsearch.common.io.stream.StreamOutput;
13+
import org.elasticsearch.exponentialhistogram.AbstractExponentialHistogram;
1314
import org.elasticsearch.exponentialhistogram.BucketIterator;
1415
import org.elasticsearch.exponentialhistogram.CopyableBucketIterator;
1516
import org.elasticsearch.exponentialhistogram.ExponentialHistogram;
@@ -27,7 +28,7 @@
2728
* While this implementation is optimized for a minimal memory footprint, it is still a fully compliant {@link ExponentialHistogram}
2829
* and can therefore be directly consumed for merging / quantile estimation without requiring any prior copying or decoding.
2930
*/
30-
public class CompressedExponentialHistogram extends ExponentialHistogram {
31+
public class CompressedExponentialHistogram extends AbstractExponentialHistogram {
3132

3233
private static final long SHALLOW_SIZE = RamUsageEstimator.shallowSizeOfInstance(CompressedExponentialHistogram.class);
3334

0 commit comments

Comments
 (0)