Keep input time unit when parsing TimeValues

This commit modifies TimeValue parsing to keep the input time unit. This
enables round-trip parsing from instances of String to instances of
TimeValue and vice-versa. With this, this commit removes support for the
unit "w" representing weeks, and also removes support for fractional
values of units (e.g., 0.5s).

Relates #19102
This commit is contained in:
Jason Tedor 2016-06-27 18:41:18 -04:00 committed by GitHub
parent 1e6bebb6a3
commit 2f638b5a23
24 changed files with 183 additions and 122 deletions

View File

@ -323,7 +323,6 @@
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]common[/\\]recycler[/\\]Recyclers.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]common[/\\]rounding[/\\]Rounding.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]common[/\\]unit[/\\]ByteSizeValue.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]common[/\\]unit[/\\]TimeValue.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]common[/\\]util[/\\]BigArrays.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]common[/\\]util[/\\]CancellableThreads.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]common[/\\]util[/\\]CollectionUtils.java" checks="LineLength" />

View File

@ -24,10 +24,7 @@ import java.io.IOException;
/**
* Implementers can be written to a {@linkplain StreamOutput} and read from a {@linkplain StreamInput}. This allows them to be "thrown
* across the wire" using Elasticsearch's internal protocol. If the implementer also implements equals and hashCode then a copy made by
* serializing and deserializing must be equal and have the same hashCode. It isn't required that such a copy be entirely unchanged. For
* example, {@link org.elasticsearch.common.unit.TimeValue} converts the time to nanoseconds for serialization.
* {@linkplain org.elasticsearch.common.unit.TimeValue} actually implements {@linkplain Writeable} not {@linkplain Streamable} but it has
* the same contract.
* serializing and deserializing must be equal and have the same hashCode. It isn't required that such a copy be entirely unchanged.
*
* Prefer implementing {@link Writeable} over implementing this interface where possible. Lots of code depends on this interface so this
* isn't always possible.

View File

@ -24,8 +24,7 @@ import java.io.IOException;
/**
* Implementers can be written to a {@linkplain StreamOutput} and read from a {@linkplain StreamInput}. This allows them to be "thrown
* across the wire" using Elasticsearch's internal protocol. If the implementer also implements equals and hashCode then a copy made by
* serializing and deserializing must be equal and have the same hashCode. It isn't required that such a copy be entirely unchanged. For
* example, {@link org.elasticsearch.common.unit.TimeValue} converts the time to nanoseconds for serialization.
* serializing and deserializing must be equal and have the same hashCode. It isn't required that such a copy be entirely unchanged.
*
* Prefer implementing this interface over implementing {@link Streamable} where possible. Lots of code depends on {@linkplain Streamable}
* so this isn't always possible.

View File

@ -30,14 +30,50 @@ import org.joda.time.format.PeriodFormat;
import org.joda.time.format.PeriodFormatter;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
public class TimeValue implements Writeable {
/** How many nano-seconds in one milli-second */
public static final long NSEC_PER_MSEC = 1000000;
public static final long NSEC_PER_MSEC = TimeUnit.NANOSECONDS.convert(1, TimeUnit.MILLISECONDS);
private static Map<TimeUnit, Byte> TIME_UNIT_BYTE_MAP;
private static Map<Byte, TimeUnit> BYTE_TIME_UNIT_MAP;
static {
final Map<TimeUnit, Byte> timeUnitByteMap = new HashMap<>();
timeUnitByteMap.put(TimeUnit.NANOSECONDS, (byte)0);
timeUnitByteMap.put(TimeUnit.MICROSECONDS, (byte)1);
timeUnitByteMap.put(TimeUnit.MILLISECONDS, (byte)2);
timeUnitByteMap.put(TimeUnit.SECONDS, (byte)3);
timeUnitByteMap.put(TimeUnit.MINUTES, (byte)4);
timeUnitByteMap.put(TimeUnit.HOURS, (byte)5);
timeUnitByteMap.put(TimeUnit.DAYS, (byte)6);
final Set<Byte> bytes = new HashSet<>();
for (TimeUnit value : TimeUnit.values()) {
assert timeUnitByteMap.containsKey(value) : value;
assert bytes.add(timeUnitByteMap.get(value));
}
final Map<Byte, TimeUnit> byteTimeUnitMap = new HashMap<>();
for (Map.Entry<TimeUnit, Byte> entry : timeUnitByteMap.entrySet()) {
byteTimeUnitMap.put(entry.getValue(), entry.getKey());
}
TIME_UNIT_BYTE_MAP = Collections.unmodifiableMap(timeUnitByteMap);
BYTE_TIME_UNIT_MAP = Collections.unmodifiableMap(byteTimeUnitMap);
}
public static final TimeValue MINUS_ONE = timeValueMillis(-1);
public static final TimeValue ZERO = timeValueMillis(0);
public static TimeValue timeValueNanos(long nanos) {
return new TimeValue(nanos, TimeUnit.NANOSECONDS);
@ -60,8 +96,19 @@ public class TimeValue implements Writeable {
}
private final long duration;
// visible for testing
long duration() {
return duration;
}
private final TimeUnit timeUnit;
// visible for testing
TimeUnit timeUnit() {
return timeUnit;
}
public TimeValue(long millis) {
this(millis, TimeUnit.MILLISECONDS);
}
@ -76,12 +123,13 @@ public class TimeValue implements Writeable {
*/
public TimeValue(StreamInput in) throws IOException {
duration = in.readZLong();
timeUnit = TimeUnit.NANOSECONDS;
timeUnit = BYTE_TIME_UNIT_MAP.get(in.readByte());
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeZLong(nanos());
out.writeZLong(duration);
out.writeByte(TIME_UNIT_BYTE_MAP.get(timeUnit));
}
public long nanos() {
@ -240,19 +288,19 @@ public class TimeValue implements Writeable {
}
switch (timeUnit) {
case NANOSECONDS:
return Strings.format1Decimals(duration, "nanos");
return duration + "nanos";
case MICROSECONDS:
return Strings.format1Decimals(duration, "micros");
return duration + "micros";
case MILLISECONDS:
return Strings.format1Decimals(duration, "ms");
return duration + "ms";
case SECONDS:
return Strings.format1Decimals(duration, "s");
return duration + "s";
case MINUTES:
return Strings.format1Decimals(duration, "m");
return duration + "m";
case HOURS:
return Strings.format1Decimals(duration, "h");
return duration + "h";
case DAYS:
return Strings.format1Decimals(duration, "d");
return duration + "d";
default:
throw new IllegalArgumentException("unknown time unit: " + timeUnit.name());
}
@ -270,47 +318,48 @@ public class TimeValue implements Writeable {
return defaultValue;
}
try {
long millis;
String lowerSValue = sValue.toLowerCase(Locale.ROOT).trim();
if (lowerSValue.endsWith("ms")) {
millis = parse(lowerSValue, 2, 1);
if (lowerSValue.endsWith("nanos")) {
return new TimeValue(parse(lowerSValue, 5), TimeUnit.NANOSECONDS);
} else if (lowerSValue.endsWith("micros")) {
return new TimeValue(parse(lowerSValue, 6), TimeUnit.MICROSECONDS);
} else if (lowerSValue.endsWith("ms")) {
return new TimeValue(parse(lowerSValue, 2), TimeUnit.MILLISECONDS);
} else if (lowerSValue.endsWith("s")) {
millis = parse(lowerSValue, 1, 1000);
return new TimeValue(parse(lowerSValue, 1), TimeUnit.SECONDS);
} else if (lowerSValue.endsWith("m")) {
millis = parse(lowerSValue, 1, 60 * 1000);
return new TimeValue(parse(lowerSValue, 1), TimeUnit.MINUTES);
} else if (lowerSValue.endsWith("h")) {
millis = parse(lowerSValue, 1, 60 * 60 * 1000);
return new TimeValue(parse(lowerSValue, 1), TimeUnit.HOURS);
} else if (lowerSValue.endsWith("d")) {
millis = parse(lowerSValue, 1, 24 * 60 * 60 * 1000);
} else if (lowerSValue.endsWith("w")) {
millis = parse(lowerSValue, 1, 7 * 24 * 60 * 60 * 1000);
} else if (lowerSValue.equals("-1")) {
// Allow this special value to be unit-less:
millis = -1;
} else if (lowerSValue.equals("0")) {
// Allow this special value to be unit-less:
millis = 0;
return new TimeValue(parse(lowerSValue, 1), TimeUnit.DAYS);
} else if (lowerSValue.matches("-0*1")) {
return TimeValue.MINUS_ONE;
} else if (lowerSValue.matches("0+")) {
return TimeValue.ZERO;
} else {
// Missing units:
throw new ElasticsearchParseException("Failed to parse setting [{}] with value [{}] as a time value: unit is missing or unrecognized", settingName, sValue);
throw new ElasticsearchParseException(
"failed to parse setting [{}] with value [{}] as a time value: unit is missing or unrecognized",
settingName,
sValue);
}
return new TimeValue(millis, TimeUnit.MILLISECONDS);
} catch (NumberFormatException e) {
throw new ElasticsearchParseException("Failed to parse [{}]", e, sValue);
throw new ElasticsearchParseException("failed to parse [{}]", e, sValue);
}
}
private static long parse(String s, int suffixLength, long scale) {
return (long) (Double.parseDouble(s.substring(0, s.length() - suffixLength)) * scale);
private static long parse(String s, int suffixLength) {
return Long.parseLong(s.substring(0, s.length() - suffixLength).trim());
}
static final long C0 = 1L;
static final long C1 = C0 * 1000L;
static final long C2 = C1 * 1000L;
static final long C3 = C2 * 1000L;
static final long C4 = C3 * 60L;
static final long C5 = C4 * 60L;
static final long C6 = C5 * 24L;
private static final long C0 = 1L;
private static final long C1 = C0 * 1000L;
private static final long C2 = C1 * 1000L;
private static final long C3 = C2 * 1000L;
private static final long C4 = C3 * 60L;
private static final long C5 = C4 * 60L;
private static final long C6 = C5 * 24L;
@Override
public boolean equals(Object o) {

View File

@ -685,7 +685,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> imp
if (source.profile()) {
context.setProfilers(new Profilers(context.searcher()));
}
context.timeoutInMillis(source.timeoutInMillis());
context.timeout(source.timeout());
context.terminateAfter(source.terminateAfter());
if (source.aggregations() != null) {
try {

View File

@ -143,7 +143,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ
private Float minScore;
private long timeoutInMillis = -1;
private TimeValue timeout = null;
private int terminateAfter = SearchContext.DEFAULT_TERMINATE_AFTER;
private List<String> fieldNames;
@ -241,7 +241,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ
}
suggestBuilder = in.readOptionalWriteable(SuggestBuilder::new);
terminateAfter = in.readVInt();
timeoutInMillis = in.readLong();
timeout = in.readOptionalWriteable(TimeValue::new);
trackScores = in.readBoolean();
version = in.readOptionalBoolean();
ext = in.readOptionalBytesReference();
@ -320,7 +320,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ
}
out.writeOptionalWriteable(suggestBuilder);
out.writeVInt(terminateAfter);
out.writeLong(timeoutInMillis);
out.writeOptionalWriteable(timeout);
out.writeBoolean(trackScores);
out.writeOptionalBoolean(version);
out.writeOptionalBytesReference(ext);
@ -446,15 +446,15 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ
* An optional timeout to control how long search is allowed to take.
*/
public SearchSourceBuilder timeout(TimeValue timeout) {
this.timeoutInMillis = timeout.millis();
this.timeout = timeout;
return this;
}
/**
* Gets the timeout to control how long search is allowed to take.
*/
public long timeoutInMillis() {
return timeoutInMillis;
public TimeValue timeout() {
return timeout;
}
/**
@ -928,7 +928,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ
rewrittenBuilder.stats = stats;
rewrittenBuilder.suggestBuilder = suggestBuilder;
rewrittenBuilder.terminateAfter = terminateAfter;
rewrittenBuilder.timeoutInMillis = timeoutInMillis;
rewrittenBuilder.timeout = timeout;
rewrittenBuilder.trackScores = trackScores;
rewrittenBuilder.version = version;
return rewrittenBuilder;
@ -958,7 +958,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ
} else if (context.getParseFieldMatcher().match(currentFieldName, SIZE_FIELD)) {
size = parser.intValue();
} else if (context.getParseFieldMatcher().match(currentFieldName, TIMEOUT_FIELD)) {
timeoutInMillis = TimeValue.parseTimeValue(parser.text(), null, TIMEOUT_FIELD.getPreferredName()).millis();
timeout = TimeValue.parseTimeValue(parser.text(), null, TIMEOUT_FIELD.getPreferredName());
} else if (context.getParseFieldMatcher().match(currentFieldName, TERMINATE_AFTER_FIELD)) {
terminateAfter = parser.intValue();
} else if (context.getParseFieldMatcher().match(currentFieldName, MIN_SCORE_FIELD)) {
@ -1095,8 +1095,8 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ
builder.field(SIZE_FIELD.getPreferredName(), size);
}
if (timeoutInMillis != -1) {
builder.field(TIMEOUT_FIELD.getPreferredName(), TimeValue.timeValueMillis(timeoutInMillis).toString());
if (timeout != null && !timeout.equals(TimeValue.MINUS_ONE)) {
builder.field(TIMEOUT_FIELD.getPreferredName(), timeout.getStringRep());
}
if (terminateAfter != SearchContext.DEFAULT_TERMINATE_AFTER) {
@ -1341,7 +1341,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ
public int hashCode() {
return Objects.hash(aggregations, explain, fetchSourceContext, fieldDataFields, fieldNames, from,
highlightBuilder, indexBoost, minScore, postQueryBuilder, queryBuilder, rescoreBuilders, scriptFields,
size, sorts, searchAfterBuilder, sliceBuilder, stats, suggestBuilder, terminateAfter, timeoutInMillis, trackScores, version, profile);
size, sorts, searchAfterBuilder, sliceBuilder, stats, suggestBuilder, terminateAfter, timeout, trackScores, version, profile);
}
@Override
@ -1373,7 +1373,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ
&& Objects.equals(stats, other.stats)
&& Objects.equals(suggestBuilder, other.suggestBuilder)
&& Objects.equals(terminateAfter, other.terminateAfter)
&& Objects.equals(timeoutInMillis, other.timeoutInMillis)
&& Objects.equals(timeout, other.timeout)
&& Objects.equals(trackScores, other.trackScores)
&& Objects.equals(version, other.version)
&& Objects.equals(profile, other.profile);

View File

@ -24,8 +24,8 @@ import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.FieldDoc;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.Counter;
import org.elasticsearch.action.search.SearchType;
@ -99,8 +99,7 @@ public class DefaultSearchContext extends SearchContext {
private final QuerySearchResult queryResult;
private final FetchSearchResult fetchResult;
private float queryBoost = 1.0f;
// timeout in millis
private long timeoutInMillis;
private TimeValue timeout;
// terminate after count
private int terminateAfter = DEFAULT_TERMINATE_AFTER;
private List<String> groupStats;
@ -174,7 +173,7 @@ public class DefaultSearchContext extends SearchContext {
this.indexService = indexService;
this.searcher = new ContextIndexSearcher(engineSearcher, indexService.cache().query(), indexShard.getQueryCachingPolicy());
this.timeEstimateCounter = timeEstimateCounter;
this.timeoutInMillis = timeout.millis();
this.timeout = timeout;
queryShardContext = indexService.newQueryShardContext(searcher.getIndexReader());
queryShardContext.setTypes(request.types());
}
@ -512,13 +511,13 @@ public class DefaultSearchContext extends SearchContext {
}
@Override
public long timeoutInMillis() {
return timeoutInMillis;
public TimeValue timeout() {
return timeout;
}
@Override
public void timeoutInMillis(long timeoutInMillis) {
this.timeoutInMillis = timeoutInMillis;
public void timeout(TimeValue timeout) {
this.timeout = timeout;
}
@Override

View File

@ -25,6 +25,7 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.util.Counter;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.index.analysis.AnalysisService;
import org.elasticsearch.index.cache.bitset.BitsetFilterCache;
@ -264,13 +265,13 @@ public abstract class FilteredSearchContext extends SearchContext {
}
@Override
public long timeoutInMillis() {
return in.timeoutInMillis();
public TimeValue timeout() {
return in.timeout();
}
@Override
public void timeoutInMillis(long timeoutInMillis) {
in.timeoutInMillis(timeoutInMillis);
public void timeout(TimeValue timeout) {
in.timeout(timeout);
}
@Override

View File

@ -28,6 +28,7 @@ import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.lease.Releasable;
import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.common.util.iterable.Iterables;
import org.elasticsearch.index.analysis.AnalysisService;
@ -226,9 +227,9 @@ public abstract class SearchContext implements Releasable {
public abstract IndexFieldDataService fieldData();
public abstract long timeoutInMillis();
public abstract TimeValue timeout();
public abstract void timeoutInMillis(long timeoutInMillis);
public abstract void timeout(TimeValue timeout);
public abstract int terminateAfter();

View File

@ -20,6 +20,7 @@ package org.elasticsearch.search.internal;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.Counter;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.ParsedQuery;
import org.elasticsearch.search.aggregations.SearchContextAggregations;
import org.elasticsearch.search.fetch.FetchSearchResult;
@ -155,7 +156,7 @@ public class SubSearchContext extends FilteredSearchContext {
}
@Override
public void timeoutInMillis(long timeoutInMillis) {
public void timeout(TimeValue timeout) {
throw new UnsupportedOperationException("Not supported");
}

View File

@ -349,12 +349,12 @@ public class QueryPhase implements SearchPhase {
}
}
final boolean timeoutSet = searchContext.timeoutInMillis() != SearchService.NO_TIMEOUT.millis();
final boolean timeoutSet = searchContext.timeout() != null && !searchContext.timeout().equals(SearchService.NO_TIMEOUT);
if (timeoutSet && collector != null) { // collector might be null if no collection is actually needed
final Collector child = collector;
// TODO: change to use our own counter that uses the scheduler in ThreadPool
// throws TimeLimitingCollector.TimeExceededException when timeout has reached
collector = Lucene.wrapTimeLimitingCollector(collector, searchContext.timeEstimateCounter(), searchContext.timeoutInMillis());
collector = Lucene.wrapTimeLimitingCollector(collector, searchContext.timeEstimateCounter(), searchContext.timeout().millis());
if (doProfile) {
collector = new InternalProfileCollector(collector, CollectorResult.REASON_SEARCH_TIMEOUT,
Collections.singletonList((InternalProfileCollector) child));

View File

@ -263,7 +263,7 @@ public class ClusterSettingsIT extends ESIntegTestCase {
.get();
fail("bogus value");
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [discovery.zen.publish_timeout] with value [whatever] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [discovery.zen.publish_timeout] with value [whatever] as a time value: unit is missing or unrecognized");
}
assertThat(discoverySettings.getPublishTimeout().seconds(), equalTo(1L));

View File

@ -85,9 +85,6 @@ public class TimeValueTests extends ESTestCase {
assertEquals(new TimeValue(10, TimeUnit.SECONDS),
TimeValue.parseTimeValue("10S", null, "test"));
assertEquals(new TimeValue(100, TimeUnit.MILLISECONDS),
TimeValue.parseTimeValue("0.1s", null, "test"));
assertEquals(new TimeValue(10, TimeUnit.MINUTES),
TimeValue.parseTimeValue("10 m", null, "test"));
assertEquals(new TimeValue(10, TimeUnit.MINUTES),
@ -115,14 +112,17 @@ public class TimeValueTests extends ESTestCase {
assertEquals(new TimeValue(10, TimeUnit.DAYS),
TimeValue.parseTimeValue("10D", null, "test"));
assertEquals(new TimeValue(70, TimeUnit.DAYS),
TimeValue.parseTimeValue("10 w", null, "test"));
assertEquals(new TimeValue(70, TimeUnit.DAYS),
TimeValue.parseTimeValue("10w", null, "test"));
assertEquals(new TimeValue(70, TimeUnit.DAYS),
TimeValue.parseTimeValue("10 W", null, "test"));
assertEquals(new TimeValue(70, TimeUnit.DAYS),
TimeValue.parseTimeValue("10W", null, "test"));
final int length = randomIntBetween(0, 8);
final String zeros = new String(new char[length]).replace('\0', '0');
assertTrue(TimeValue.parseTimeValue("-" + zeros + "1", null, "test") == TimeValue.MINUS_ONE);
assertTrue(TimeValue.parseTimeValue(zeros + "0", null, "test") == TimeValue.ZERO);
}
public void testRoundTrip() {
final String s = randomTimeValue();
assertThat(TimeValue.parseTimeValue(s, null, "test").getStringRep(), equalTo(s));
final TimeValue t = new TimeValue(randomIntBetween(1, 128), randomFrom(TimeUnit.values()));
assertThat(TimeValue.parseTimeValue(t.getStringRep(), null, "test"), equalTo(t));
}
private void assertEqualityAfterSerialize(TimeValue value, int expectedSize) throws IOException {
@ -134,13 +134,20 @@ public class TimeValueTests extends ESTestCase {
TimeValue inValue = new TimeValue(in);
assertThat(inValue, equalTo(value));
assertThat(inValue.duration(), equalTo(value.duration()));
assertThat(inValue.timeUnit(), equalTo(value.timeUnit()));
}
public void testSerialize() throws Exception {
assertEqualityAfterSerialize(new TimeValue(100, TimeUnit.DAYS), 8);
assertEqualityAfterSerialize(timeValueNanos(-1), 1);
assertEqualityAfterSerialize(timeValueNanos(1), 1);
assertEqualityAfterSerialize(timeValueSeconds(30), 6);
assertEqualityAfterSerialize(new TimeValue(100, TimeUnit.DAYS), 3);
assertEqualityAfterSerialize(timeValueNanos(-1), 2);
assertEqualityAfterSerialize(timeValueNanos(1), 2);
assertEqualityAfterSerialize(timeValueSeconds(30), 2);
final TimeValue timeValue = new TimeValue(randomIntBetween(0, 1024), randomFrom(TimeUnit.values()));
BytesStreamOutput out = new BytesStreamOutput();
out.writeZLong(timeValue.duration());
assertEqualityAfterSerialize(timeValue, 1 + out.bytes().length());
}
public void testFailOnUnknownUnits() {
@ -148,7 +155,7 @@ public class TimeValueTests extends ESTestCase {
TimeValue.parseTimeValue("23tw", null, "test");
fail("Expected ElasticsearchParseException");
} catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), containsString("Failed to parse"));
assertThat(e.getMessage(), containsString("failed to parse"));
}
}
@ -157,7 +164,7 @@ public class TimeValueTests extends ESTestCase {
TimeValue.parseTimeValue("42", null, "test");
fail("Expected ElasticsearchParseException");
} catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), containsString("Failed to parse"));
assertThat(e.getMessage(), containsString("failed to parse"));
}
}
@ -166,7 +173,7 @@ public class TimeValueTests extends ESTestCase {
TimeValue.parseTimeValue("42ms.", null, "test");
fail("Expected ElasticsearchParseException");
} catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), containsString("Failed to parse"));
assertThat(e.getMessage(), containsString("failed to parse"));
}
}

View File

@ -176,28 +176,28 @@ public class IndexingSlowLogTests extends ESTestCase {
settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(IndexingSlowLog.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_TRACE_SETTING.getKey(), "NOT A TIME VALUE").build()));
fail();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [index.indexing.slowlog.threshold.index.trace] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [index.indexing.slowlog.threshold.index.trace] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
}
try {
settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(IndexingSlowLog.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_DEBUG_SETTING.getKey(), "NOT A TIME VALUE").build()));
fail();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [index.indexing.slowlog.threshold.index.debug] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [index.indexing.slowlog.threshold.index.debug] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
}
try {
settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(IndexingSlowLog.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_INFO_SETTING.getKey(), "NOT A TIME VALUE").build()));
fail();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [index.indexing.slowlog.threshold.index.info] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [index.indexing.slowlog.threshold.index.info] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
}
try {
settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(IndexingSlowLog.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_WARN_SETTING.getKey(), "NOT A TIME VALUE").build()));
fail();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [index.indexing.slowlog.threshold.index.warn] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [index.indexing.slowlog.threshold.index.warn] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
}
}

View File

@ -249,28 +249,28 @@ public class SearchSlowLogTests extends ESSingleNodeTestCase {
settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_TRACE_SETTING.getKey(), "NOT A TIME VALUE").build()));
fail();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [index.search.slowlog.threshold.query.trace] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [index.search.slowlog.threshold.query.trace] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
}
try {
settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_DEBUG_SETTING.getKey(), "NOT A TIME VALUE").build()));
fail();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [index.search.slowlog.threshold.query.debug] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [index.search.slowlog.threshold.query.debug] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
}
try {
settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_INFO_SETTING.getKey(), "NOT A TIME VALUE").build()));
fail();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [index.search.slowlog.threshold.query.info] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [index.search.slowlog.threshold.query.info] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
}
try {
settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_WARN_SETTING.getKey(), "NOT A TIME VALUE").build()));
fail();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [index.search.slowlog.threshold.query.warn] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [index.search.slowlog.threshold.query.warn] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
}
}
@ -320,28 +320,28 @@ public class SearchSlowLogTests extends ESSingleNodeTestCase {
settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_TRACE_SETTING.getKey(), "NOT A TIME VALUE").build()));
fail();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [index.search.slowlog.threshold.fetch.trace] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [index.search.slowlog.threshold.fetch.trace] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
}
try {
settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_DEBUG_SETTING.getKey(), "NOT A TIME VALUE").build()));
fail();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [index.search.slowlog.threshold.fetch.debug] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [index.search.slowlog.threshold.fetch.debug] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
}
try {
settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_INFO_SETTING.getKey(), "NOT A TIME VALUE").build()));
fail();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [index.search.slowlog.threshold.fetch.info] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [index.search.slowlog.threshold.fetch.info] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
}
try {
settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(SearchSlowLog.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_WARN_SETTING.getKey(), "NOT A TIME VALUE").build()));
fail();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Failed to parse setting [index.search.slowlog.threshold.fetch.warn] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
assertEquals(ex.getMessage(), "failed to parse setting [index.search.slowlog.threshold.fetch.warn] with value [NOT A TIME VALUE] as a time value: unit is missing or unrecognized");
}
}

View File

@ -139,7 +139,7 @@ public class TTLMappingTests extends ESSingleNodeTestCase {
String updatedMapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_ttl")
.field("default", "1w")
.field("default", "7d")
.endObject()
.startObject("properties").field("field").startObject().field("type", "text").endObject().endObject()
.endObject().endObject().string();

View File

@ -140,7 +140,7 @@ public class PipelineExecutionServiceTests extends ESTestCase {
IngestDocument ingestDocument = (IngestDocument) invocationOnMock.getArguments()[0];
for (IngestDocument.MetaData metaData : IngestDocument.MetaData.values()) {
if (metaData == IngestDocument.MetaData.TTL) {
ingestDocument.setFieldValue(IngestDocument.MetaData.TTL.getFieldName(), "5w");
ingestDocument.setFieldValue(IngestDocument.MetaData.TTL.getFieldName(), "35d");
} else {
ingestDocument.setFieldValue(metaData.getFieldName(), "update" + metaData.getFieldName());
}

View File

@ -86,7 +86,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.test.ClusterServiceUtils.createClusterService;
import static org.elasticsearch.test.ClusterServiceUtils.setState;
@ -208,7 +207,7 @@ public class SearchSourceBuilderTests extends ESTestCase {
builder.minScore(randomFloat() * 1000);
}
if (randomBoolean()) {
builder.timeout(new TimeValue(randomIntBetween(1, 100), randomFrom(TimeUnit.values())));
builder.timeout(TimeValue.parseTimeValue(randomTimeValue(), null, "timeout"));
}
if (randomBoolean()) {
builder.terminateAfter(randomIntBetween(1, 100000));
@ -456,7 +455,7 @@ public class SearchSourceBuilderTests extends ESTestCase {
public void testEqualsAndHashcode() throws IOException {
SearchSourceBuilder firstBuilder = createSearchSourceBuilder();
assertFalse("source builder is equal to null", firstBuilder.equals(null));
assertNotNull("source builder is equal to null", firstBuilder);
assertFalse("source builder is equal to incompatible type", firstBuilder.equals(""));
assertTrue("source builder is not equal to self", firstBuilder.equals(firstBuilder));
assertThat("same source builder's hashcode returns different values if called multiple times", firstBuilder.hashCode(),
@ -601,7 +600,7 @@ public class SearchSourceBuilderTests extends ESTestCase {
final String query = "{ \"query\": { \"match_all\": {}}, \"timeout\": \"" + timeout + "\"}";
try (XContentParser parser = XContentFactory.xContent(query).createParser(query)) {
final SearchSourceBuilder builder = SearchSourceBuilder.fromXContent(createParseContext(parser), aggParsers, suggesters);
assertThat(builder.timeoutInMillis(), equalTo(TimeValue.parseTimeValue(timeout, null, "timeout").millis()));
assertThat(builder.timeout(), equalTo(TimeValue.parseTimeValue(timeout, null, "timeout")));
}
}

View File

@ -594,9 +594,9 @@ public class DecayFunctionScoreIT extends ESIntegTestCase {
searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source(
searchSource().query(
functionScoreQuery(QueryBuilders.matchAllQuery(), new FilterFunctionBuilder[]{
new FilterFunctionBuilder(linearDecayFunction("num1", null, "1000w")),
new FilterFunctionBuilder(linearDecayFunction("num1", null, "7000d")),
new FilterFunctionBuilder(gaussDecayFunction("num1", null, "1d")),
new FilterFunctionBuilder(exponentialDecayFunction("num1", null, "1000w"))
new FilterFunctionBuilder(exponentialDecayFunction("num1", null, "7000d"))
}).scoreMode(FiltersFunctionScoreQuery.ScoreMode.MULTIPLY))));
SearchResponse sr = response.actionGet();

View File

@ -220,7 +220,7 @@ public class SimpleVersioningIT extends ESIntegTestCase {
fail("did not hit expected exception");
} catch (IllegalArgumentException iae) {
// expected
assertTrue(iae.getMessage().contains("Failed to parse setting [index.gc_deletes] with value [42] as a time value: unit is missing or unrecognized"));
assertTrue(iae.getMessage().contains("failed to parse setting [index.gc_deletes] with value [42] as a time value: unit is missing or unrecognized"));
}
}

View File

@ -286,3 +286,11 @@ The setting `bootstrap.mlockall` has been renamed to
The default setting `include_global_state` for restoring snapshots has been
changed from `true` to `false`. It has not been changed for taking snapshots and
still defaults to `true` in that case.
==== Time value parsing
The unit 'w' representing weeks is no longer supported.
Fractional time values (e.g., 0.5s) are no longer supported. For
example, this means when setting timeouts "0.5s" will be rejected and
should instead be input as "500ms".

View File

@ -413,7 +413,7 @@ public abstract class ESTestCase extends LuceneTestCase {
return generateRandomStringArray(maxArraySize, maxStringSize, allowNull, true);
}
private static String[] TIME_SUFFIXES = new String[]{"d", "H", "ms", "s", "S", "w"};
private static String[] TIME_SUFFIXES = new String[]{"d", "h", "ms", "s", "m"};
private static String randomTimeValue(int lower, int upper) {
return randomIntBetween(lower, upper) + randomFrom(TIME_SUFFIXES);

View File

@ -410,12 +410,12 @@ public final class InternalTestCluster extends TestCluster {
builder.put("cache.recycler.page.type", RandomPicks.randomFrom(random, PageCacheRecycler.Type.values()));
}
if (random.nextInt(10) == 0) { // 10% of the nodes have a very frequent check interval
builder.put(SearchService.KEEPALIVE_INTERVAL_SETTING.getKey(), TimeValue.timeValueMillis(10 + random.nextInt(2000)));
builder.put(SearchService.KEEPALIVE_INTERVAL_SETTING.getKey(), TimeValue.timeValueMillis(10 + random.nextInt(2000)).getStringRep());
} else if (random.nextInt(10) != 0) { // 90% of the time - 10% of the time we don't set anything
builder.put(SearchService.KEEPALIVE_INTERVAL_SETTING.getKey(), TimeValue.timeValueSeconds(10 + random.nextInt(5 * 60)));
builder.put(SearchService.KEEPALIVE_INTERVAL_SETTING.getKey(), TimeValue.timeValueSeconds(10 + random.nextInt(5 * 60)).getStringRep());
}
if (random.nextBoolean()) { // sometimes set a
builder.put(SearchService.DEFAULT_KEEPALIVE_SETTING.getKey(), TimeValue.timeValueSeconds(100 + random.nextInt(5 * 60)));
builder.put(SearchService.DEFAULT_KEEPALIVE_SETTING.getKey(), TimeValue.timeValueSeconds(100 + random.nextInt(5 * 60)).getStringRep());
}
builder.put(EsExecutors.PROCESSORS_SETTING.getKey(), 1 + random.nextInt(3));
@ -469,7 +469,7 @@ public final class InternalTestCluster extends TestCluster {
builder.put(ScriptService.SCRIPT_CACHE_SIZE_SETTING.getKey(), RandomInts.randomIntBetween(random, 0, 2000));
}
if (random.nextBoolean()) {
builder.put(ScriptService.SCRIPT_CACHE_EXPIRE_SETTING.getKey(), TimeValue.timeValueMillis(RandomInts.randomIntBetween(random, 750, 10000000)));
builder.put(ScriptService.SCRIPT_CACHE_EXPIRE_SETTING.getKey(), TimeValue.timeValueMillis(RandomInts.randomIntBetween(random, 750, 10000000)).getStringRep());
}
return builder.build();

View File

@ -28,6 +28,7 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.util.Counter;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.analysis.AnalysisService;
@ -311,12 +312,12 @@ public class TestSearchContext extends SearchContext {
}
@Override
public long timeoutInMillis() {
return 0;
public TimeValue timeout() {
return TimeValue.ZERO;
}
@Override
public void timeoutInMillis(long timeoutInMillis) {
public void timeout(TimeValue timeout) {
}
@Override