diff --git a/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java b/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java index a833e16946b..60befb9577a 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java @@ -334,7 +334,7 @@ public class QueryShardContext extends QueryRewriteContext { * Compiles (or retrieves from cache) and binds the parameters to the * provided script */ - public SearchScript getSearchScript(Script script, ScriptContext context, Map params) { + public final SearchScript getSearchScript(Script script, ScriptContext context, Map params) { failIfFrozen(); return scriptService.search(lookup(), script, context, params); } @@ -342,7 +342,7 @@ public class QueryShardContext extends QueryRewriteContext { * Returns a lazily created {@link SearchScript} that is compiled immediately but can be pulled later once all * parameters are available. */ - public Function, SearchScript> getLazySearchScript(Script script, ScriptContext context, + public final Function, SearchScript> getLazySearchScript(Script script, ScriptContext context, Map params) { failIfFrozen(); CompiledScript compile = scriptService.compile(script, context, params); @@ -353,7 +353,7 @@ public class QueryShardContext extends QueryRewriteContext { * Compiles (or retrieves from cache) and binds the parameters to the * provided script */ - public ExecutableScript getExecutableScript(Script script, ScriptContext context, Map params) { + public final ExecutableScript getExecutableScript(Script script, ScriptContext context, Map params) { failIfFrozen(); return scriptService.executable(script, context, params); } @@ -362,7 +362,7 @@ public class QueryShardContext extends QueryRewriteContext { * Returns a lazily created {@link ExecutableScript} that is compiled immediately but can be pulled later once all * parameters are available. */ - public Function, ExecutableScript> getLazyExecutableScript(Script script, ScriptContext context, + public final Function, ExecutableScript> getLazyExecutableScript(Script script, ScriptContext context, Map params) { failIfFrozen(); CompiledScript executable = scriptService.compile(script, context, params); @@ -373,15 +373,20 @@ public class QueryShardContext extends QueryRewriteContext { * if this method is called the query context will throw exception if methods are accessed * that could yield different results across executions like {@link #getTemplateBytes(Script)} */ - public void freezeContext() { + public final void freezeContext() { this.frozen.set(Boolean.TRUE); } /** - * This method fails if {@link #freezeContext()} is called before on this context. - * This is used to seal + * This method fails if {@link #freezeContext()} is called before on this + * context. This is used to seal. + * + * This methods and all methods that call it should be final to ensure that + * setting the request as not cacheable and the freezing behaviour of this + * class cannot be bypassed. This is important so we can trust when this + * class says a request can be cached. */ - protected void failIfFrozen() { + protected final void failIfFrozen() { this.cachable = false; if (frozen.get() == Boolean.TRUE) { throw new IllegalArgumentException("features that prevent cachability are disabled on this context"); @@ -391,7 +396,7 @@ public class QueryShardContext extends QueryRewriteContext { } @Override - public BytesReference getTemplateBytes(Script template) { + public final BytesReference getTemplateBytes(Script template) { failIfFrozen(); return super.getTemplateBytes(template); } @@ -399,7 +404,7 @@ public class QueryShardContext extends QueryRewriteContext { /** * Returns true iff the result of the processed search request is cachable. Otherwise false */ - public boolean isCachable() { + public final boolean isCachable() { return cachable; } @@ -410,7 +415,8 @@ public class QueryShardContext extends QueryRewriteContext { return shardId; } - public long nowInMillis() { + @Override + public final long nowInMillis() { failIfFrozen(); return super.nowInMillis(); } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/histogram/ExtendedBoundsTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/histogram/ExtendedBoundsTests.java index f65d7eb1f7b..e2609f97eaa 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/histogram/ExtendedBoundsTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/histogram/ExtendedBoundsTests.java @@ -19,23 +19,26 @@ package org.elasticsearch.search.aggregations.bucket.histogram; +import org.elasticsearch.Version; +import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.Joda; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.SearchParseException; import org.elasticsearch.search.aggregations.bucket.histogram.ExtendedBounds; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.threadpool.ThreadPoolStats; import org.joda.time.DateTimeZone; import org.joda.time.Instant; @@ -93,10 +96,13 @@ public class ExtendedBoundsTests extends ESTestCase { public void testParseAndValidate() { long now = randomLong(); + Settings indexSettings = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) + .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1).put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 1).build(); SearchContext context = mock(SearchContext.class); - QueryShardContext qsc = mock(QueryShardContext.class); + QueryShardContext qsc = new QueryShardContext(0, + new IndexSettings(IndexMetaData.builder("foo").settings(indexSettings).build(), indexSettings), null, null, null, null, + null, null, null, null, null, () -> now); when(context.getQueryShardContext()).thenReturn(qsc); - when(qsc.nowInMillis()).thenReturn(now); FormatDateTimeFormatter formatter = Joda.forPattern("dateOptionalTime"); DocValueFormat format = new DocValueFormat.DateTime(formatter, DateTimeZone.UTC);