diff --git a/libs/core/src/main/java/org/elasticsearch/core/TimeValue.java b/libs/core/src/main/java/org/elasticsearch/core/TimeValue.java index 30883ef3af731..df7c47943289d 100644 --- a/libs/core/src/main/java/org/elasticsearch/core/TimeValue.java +++ b/libs/core/src/main/java/org/elasticsearch/core/TimeValue.java @@ -17,9 +17,11 @@ public class TimeValue implements Comparable { /** How many nano-seconds in one milli-second */ public static final long NSEC_PER_MSEC = TimeUnit.NANOSECONDS.convert(1, TimeUnit.MILLISECONDS); - public static final TimeValue MINUS_ONE = timeValueMillis(-1); - public static final TimeValue ZERO = timeValueMillis(0); - public static final TimeValue MAX_VALUE = TimeValue.timeValueNanos(Long.MAX_VALUE); + public static final TimeValue MINUS_ONE = new TimeValue(-1, TimeUnit.MILLISECONDS); + public static final TimeValue ZERO = new TimeValue(0, TimeUnit.MILLISECONDS); + public static final TimeValue MAX_VALUE = new TimeValue(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + public static final TimeValue THIRTY_SECONDS = new TimeValue(30, TimeUnit.SECONDS); + public static final TimeValue ONE_MINUTE = new TimeValue(1, TimeUnit.MINUTES); private static final long C0 = 1L; private static final long C1 = C0 * 1000L; @@ -49,14 +51,28 @@ public static TimeValue timeValueNanos(long nanos) { } public static TimeValue timeValueMillis(long millis) { + if (millis == 0) { + return ZERO; + } + if (millis == -1) { + return MINUS_ONE; + } return new TimeValue(millis, TimeUnit.MILLISECONDS); } public static TimeValue timeValueSeconds(long seconds) { + if (seconds == 30) { + // common value, no need to allocate each time + return THIRTY_SECONDS; + } return new TimeValue(seconds, TimeUnit.SECONDS); } public static TimeValue timeValueMinutes(long minutes) { + if (minutes == 1) { + // common value, no need to allocate each time + return ONE_MINUTE; + } return new TimeValue(minutes, TimeUnit.MINUTES); } @@ -355,18 +371,18 @@ public static TimeValue parseTimeValue(@Nullable String sValue, TimeValue defaul } final String normalized = sValue.toLowerCase(Locale.ROOT).trim(); if (normalized.endsWith("nanos")) { - return new TimeValue(parse(sValue, normalized, "nanos", settingName), TimeUnit.NANOSECONDS); + return TimeValue.timeValueNanos(parse(sValue, normalized, "nanos", settingName)); } else if (normalized.endsWith("micros")) { return new TimeValue(parse(sValue, normalized, "micros", settingName), TimeUnit.MICROSECONDS); } else if (normalized.endsWith("ms")) { - return new TimeValue(parse(sValue, normalized, "ms", settingName), TimeUnit.MILLISECONDS); + return TimeValue.timeValueMillis(parse(sValue, normalized, "ms", settingName)); } else if (normalized.endsWith("s")) { - return new TimeValue(parse(sValue, normalized, "s", settingName), TimeUnit.SECONDS); + return TimeValue.timeValueSeconds(parse(sValue, normalized, "s", settingName)); } else if (sValue.endsWith("m")) { // parsing minutes should be case-sensitive as 'M' means "months", not "minutes"; this is the only special case. - return new TimeValue(parse(sValue, normalized, "m", settingName), TimeUnit.MINUTES); + return TimeValue.timeValueMinutes(parse(sValue, normalized, "m", settingName)); } else if (normalized.endsWith("h")) { - return new TimeValue(parse(sValue, normalized, "h", settingName), TimeUnit.HOURS); + return TimeValue.timeValueHours(parse(sValue, normalized, "h", settingName)); } else if (normalized.endsWith("d")) { return new TimeValue(parse(sValue, normalized, "d", settingName), TimeUnit.DAYS); } else if (normalized.matches("-0*1")) { diff --git a/libs/core/src/test/java/org/elasticsearch/common/unit/TimeValueTests.java b/libs/core/src/test/java/org/elasticsearch/common/unit/TimeValueTests.java index a021299aaa06d..b6481db9b9951 100644 --- a/libs/core/src/test/java/org/elasticsearch/common/unit/TimeValueTests.java +++ b/libs/core/src/test/java/org/elasticsearch/common/unit/TimeValueTests.java @@ -242,4 +242,16 @@ private TimeUnit randomTimeUnitObject() { TimeUnit.DAYS ); } + + public void testInternedValues() { + assertSame(TimeValue.timeValueMillis(-1), TimeValue.MINUS_ONE); + assertSame(TimeValue.timeValueMillis(0), TimeValue.ZERO); + assertSame(TimeValue.timeValueSeconds(30), TimeValue.THIRTY_SECONDS); + assertSame(TimeValue.timeValueMinutes(1), TimeValue.ONE_MINUTE); + + assertSame(TimeValue.parseTimeValue("-1", getTestName()), TimeValue.MINUS_ONE); + assertSame(TimeValue.parseTimeValue("0", getTestName()), TimeValue.ZERO); + assertSame(TimeValue.parseTimeValue("30s", getTestName()), TimeValue.THIRTY_SECONDS); + assertSame(TimeValue.parseTimeValue("1m", getTestName()), TimeValue.ONE_MINUTE); + } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/health/ClusterHealthRequest.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/health/ClusterHealthRequest.java index 75313227a6dda..a94555f1dfd1c 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/health/ClusterHealthRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/health/ClusterHealthRequest.java @@ -24,13 +24,12 @@ import java.io.IOException; import java.util.Map; -import java.util.concurrent.TimeUnit; public class ClusterHealthRequest extends MasterNodeReadRequest implements IndicesRequest.Replaceable { private String[] indices; private IndicesOptions indicesOptions = IndicesOptions.lenientExpandHidden(); - private TimeValue timeout = new TimeValue(30, TimeUnit.SECONDS); + private TimeValue timeout = TimeValue.timeValueSeconds(30); private ClusterHealthStatus waitForStatus; private boolean waitForNoRelocatingShards = false; private boolean waitForNoInitializingShards = false; diff --git a/server/src/main/java/org/elasticsearch/action/support/replication/ReplicationRequest.java b/server/src/main/java/org/elasticsearch/action/support/replication/ReplicationRequest.java index 1da69d76ebc82..8d388e7c6d4d6 100644 --- a/server/src/main/java/org/elasticsearch/action/support/replication/ReplicationRequest.java +++ b/server/src/main/java/org/elasticsearch/action/support/replication/ReplicationRequest.java @@ -25,7 +25,6 @@ import java.io.IOException; import java.util.Map; -import java.util.concurrent.TimeUnit; import static org.elasticsearch.action.ValidateActions.addValidationError; @@ -35,7 +34,7 @@ */ public abstract class ReplicationRequest> extends ActionRequest implements IndicesRequest { - public static final TimeValue DEFAULT_TIMEOUT = new TimeValue(1, TimeUnit.MINUTES); + public static final TimeValue DEFAULT_TIMEOUT = TimeValue.timeValueMinutes(1); /** * Target shard the request should execute on. In case of index and delete requests, diff --git a/server/src/main/java/org/elasticsearch/action/support/single/instance/InstanceShardOperationRequest.java b/server/src/main/java/org/elasticsearch/action/support/single/instance/InstanceShardOperationRequest.java index e689492523838..51952059d7d94 100644 --- a/server/src/main/java/org/elasticsearch/action/support/single/instance/InstanceShardOperationRequest.java +++ b/server/src/main/java/org/elasticsearch/action/support/single/instance/InstanceShardOperationRequest.java @@ -20,7 +20,6 @@ import org.elasticsearch.index.shard.ShardId; import java.io.IOException; -import java.util.concurrent.TimeUnit; // TODO: This request and its associated transport action can be folded into UpdateRequest which is its only concrete production code // implementation @@ -28,7 +27,7 @@ public abstract class InstanceShardOperationRequest TimeValue.timeValueMillis(duration); + case SECONDS -> TimeValue.timeValueSeconds(duration); + case MINUTES -> TimeValue.timeValueMinutes(duration); + default -> new TimeValue(duration, timeUnit); + }; } /** diff --git a/server/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java b/server/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java index f60a5a5fc601a..7799c1ff5a34c 100644 --- a/server/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java +++ b/server/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java @@ -902,6 +902,22 @@ public void testTimeValueSerialize() throws Exception { assertEqualityAfterSerialize(timeValue, 1 + out.bytes().length()); } + public void testTimeValueInterning() throws IOException { + try (var bytesOut = new BytesStreamOutput()) { + bytesOut.writeTimeValue(randomBoolean() ? TimeValue.MINUS_ONE : new TimeValue(-1, TimeUnit.MILLISECONDS)); + bytesOut.writeTimeValue(randomBoolean() ? TimeValue.ZERO : new TimeValue(0, TimeUnit.MILLISECONDS)); + bytesOut.writeTimeValue(randomBoolean() ? TimeValue.THIRTY_SECONDS : new TimeValue(30, TimeUnit.SECONDS)); + bytesOut.writeTimeValue(randomBoolean() ? TimeValue.ONE_MINUTE : new TimeValue(1, TimeUnit.MINUTES)); + + try (var in = bytesOut.bytes().streamInput()) { + assertSame(TimeValue.MINUS_ONE, in.readTimeValue()); + assertSame(TimeValue.ZERO, in.readTimeValue()); + assertSame(TimeValue.THIRTY_SECONDS, in.readTimeValue()); + assertSame(TimeValue.ONE_MINUTE, in.readTimeValue()); + } + } + } + private static class TestStreamOutput extends BytesStream { private final BytesStreamOutput output = new BytesStreamOutput();