Skip to content

Commit 68458c3

Browse files
committed
Fix withAutomaticUnit
1 parent d855b9f commit 68458c3

File tree

2 files changed

+36
-11
lines changed

2 files changed

+36
-11
lines changed

server/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,23 @@ public static ByteSizeValue of(long size, ByteSizeUnit unit) {
5656
return new ByteSizeValue(unit.toBytes(size), unit);
5757
}
5858

59+
/**
60+
* @return {@link ByteSizeValue} whose {@link #preferredUnit} is a reasonable one for human consumption.
61+
*/
5962
public static ByteSizeValue withAutomaticUnit(long sizeInBytes) {
6063
if (sizeInBytes == 0) {
6164
return ZERO;
6265
}
63-
for (int ordinal = ByteSizeUnit.values().length-1; ordinal >= 0; --ordinal) {
66+
67+
// We pick a unit such that sizeInBytes is a multiple of 1/4 of that unit.
68+
// That preserves the exact given number of bytes without using more than 2 decimal places.
69+
for (int ordinal = ByteSizeUnit.values().length - 1; ordinal >= 0; --ordinal) {
6470
ByteSizeUnit candidateUnit = ByteSizeUnit.values()[ordinal];
6571
if (candidateUnit == BYTES) {
6672
// We handle this using ofBytes below
6773
continue;
6874
}
69-
if (sizeInBytes % candidateUnit.toBytes(1) == 0) {
75+
if (sizeInBytes % (candidateUnit.toBytes(1) / 4) == 0) {
7076
return new ByteSizeValue(sizeInBytes, candidateUnit);
7177
}
7278
}

server/src/test/java/org/elasticsearch/common/unit/ByteSizeValueTests.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010
package org.elasticsearch.common.unit;
1111

12-
import com.carrotsearch.randomizedtesting.annotations.Repeat;
13-
1412
import org.elasticsearch.ElasticsearchParseException;
1513
import org.elasticsearch.common.io.stream.Writeable.Reader;
1614
import org.elasticsearch.test.AbstractWireSerializingTestCase;
@@ -32,7 +30,6 @@
3230
import static org.hamcrest.Matchers.equalTo;
3331
import static org.hamcrest.Matchers.is;
3432

35-
@Repeat(iterations = 1000)
3633
public class ByteSizeValueTests extends AbstractWireSerializingTestCase<ByteSizeValue> {
3734
public void testActualPeta() {
3835
MatcherAssert.assertThat(ByteSizeValue.of(4, PB).getBytes(), equalTo(4503599627370496L));
@@ -569,12 +566,34 @@ private static String percentToDecimal(int percent) {
569566
}
570567

571568
public void testWithAutomaticUnit() {
572-
long kibi = 1024;
573-
long mebi = kibi * kibi;
574-
assertEquals(new ByteSizeValue(kibi-1, BYTES), ByteSizeValue.withAutomaticUnit(kibi-1));
575-
assertEquals(new ByteSizeValue(kibi, KB), ByteSizeValue.withAutomaticUnit(kibi));
576-
assertEquals(new ByteSizeValue(kibi+1, BYTES), ByteSizeValue.withAutomaticUnit(kibi+1));
577-
assertEquals(new ByteSizeValue(mebi-kibi, KB), ByteSizeValue.withAutomaticUnit(mebi-kibi));
569+
for (var unit : ByteSizeUnit.values()) {
570+
if (unit == BYTES) {
571+
continue;
572+
}
573+
long bytes = unit.toBytes(1);
574+
for (int numFourths = 1; numFourths <= 8; numFourths++) {
575+
checkAutomaticUnitWithCornerCases(bytes * numFourths / 4, unit);
576+
}
577+
}
578+
}
579+
580+
private void checkAutomaticUnitWithCornerCases(long sizeInBytes, ByteSizeUnit expectedUnit) {
581+
assertEquals(
582+
sizeInBytes + " should use " + expectedUnit,
583+
new ByteSizeValue(sizeInBytes, expectedUnit),
584+
ByteSizeValue.withAutomaticUnit(sizeInBytes)
585+
);
586+
// Plus or minus one byte, it should revert to bytes
587+
assertEquals(
588+
sizeInBytes - 1 + " should use " + BYTES,
589+
new ByteSizeValue(sizeInBytes - 1, BYTES),
590+
ByteSizeValue.withAutomaticUnit(sizeInBytes - 1)
591+
);
592+
assertEquals(
593+
sizeInBytes + 1 + " should use " + BYTES,
594+
new ByteSizeValue(sizeInBytes + 1, BYTES),
595+
ByteSizeValue.withAutomaticUnit(sizeInBytes + 1)
596+
);
578597
}
579598

580599
@Override

0 commit comments

Comments
 (0)