Browse Source

Scripting: Increase ingest script cache defaults (#53765)

* Adds ability for contexts to specify their own defaults.
* Context defaults are applied if no context-specific or
  general setting exists.
* See 070ea7e for settings keys.

* Increases the per-context default for the `ingest` context.
  * Cache size is doubled, 200 compared to default of 100
  * Cache expiration is unchanged at no expiration
  * Cache max compilation is quintupled, 375/5m instead of 75/5m

Refs: #50152
Stuart Tettemer 5 năm trước cách đây
mục cha
commit
1b37d4bfc9

+ 5 - 1
server/src/main/java/org/elasticsearch/script/IngestConditionalScript.java

@@ -19,6 +19,9 @@
 
 package org.elasticsearch.script;
 
+import org.elasticsearch.common.collect.Tuple;
+import org.elasticsearch.common.unit.TimeValue;
+
 import java.util.Map;
 
 /**
@@ -29,7 +32,8 @@ public abstract class IngestConditionalScript {
     public static final String[] PARAMETERS = { "ctx" };
 
     /** The context used to compile {@link IngestConditionalScript} factories. */
-    public static final ScriptContext<Factory> CONTEXT = new ScriptContext<>("processor_conditional", Factory.class);
+    public static final ScriptContext<Factory> CONTEXT = new ScriptContext<>("processor_conditional", Factory.class,
+        200, TimeValue.timeValueMillis(0), new Tuple<>(375, TimeValue.timeValueMinutes(5)));
 
     /** The generic runtime parameters for the script. */
     private final Map<String, Object> params;

+ 5 - 1
server/src/main/java/org/elasticsearch/script/IngestScript.java

@@ -20,6 +20,9 @@
 
 package org.elasticsearch.script;
 
+import org.elasticsearch.common.collect.Tuple;
+import org.elasticsearch.common.unit.TimeValue;
+
 import java.util.Map;
 
 /**
@@ -30,7 +33,8 @@ public abstract class IngestScript {
     public static final String[] PARAMETERS = { "ctx" };
 
     /** The context used to compile {@link IngestScript} factories. */
-    public static final ScriptContext<Factory> CONTEXT = new ScriptContext<>("ingest", Factory.class);
+    public static final ScriptContext<Factory> CONTEXT = new ScriptContext<>("ingest", Factory.class,
+        200, TimeValue.timeValueMillis(0), new Tuple<>(375, TimeValue.timeValueMinutes(5)));
 
     /** The generic runtime parameters for the script. */
     private final Map<String, Object> params;

+ 26 - 2
server/src/main/java/org/elasticsearch/script/ScriptContext.java

@@ -19,6 +19,9 @@
 
 package org.elasticsearch.script;
 
+import org.elasticsearch.common.collect.Tuple;
+import org.elasticsearch.common.unit.TimeValue;
+
 import java.lang.reflect.Method;
 
 /**
@@ -68,8 +71,18 @@ public final class ScriptContext<FactoryType> {
     /** A class that is an instance of a script. */
     public final Class<?> instanceClazz;
 
-    /** Construct a context with the related instance and compiled classes. */
-    public ScriptContext(String name, Class<FactoryType> factoryClazz) {
+    /** The default size of the cache for the context if not overridden */
+    public final int cacheSizeDefault;
+
+    /** The default expiration of a script in the cache for the context, if not overridden */
+    public final TimeValue cacheExpireDefault;
+
+    /** The default max compilation rate for scripts in this context.  Script compilation is throttled if this is exceeded */
+    public final Tuple<Integer, TimeValue> maxCompilationRateDefault;
+
+    /** Construct a context with the related instance and compiled classes with caller provided cache defaults */
+    public ScriptContext(String name, Class<FactoryType> factoryClazz, int cacheSizeDefault, TimeValue cacheExpireDefault,
+                        Tuple<Integer, TimeValue> maxCompilationRateDefault) {
         this.name = name;
         this.factoryClazz = factoryClazz;
         Method newInstanceMethod = findMethod("FactoryType", factoryClazz, "newInstance");
@@ -90,6 +103,17 @@ public final class ScriptContext<FactoryType> {
                 + factoryClazz.getName() + "] for script context [" + name + "]");
         }
         instanceClazz = newInstanceMethod.getReturnType();
+
+        this.cacheSizeDefault = cacheSizeDefault;
+        this.cacheExpireDefault = cacheExpireDefault;
+        this.maxCompilationRateDefault = maxCompilationRateDefault;
+    }
+
+    /** Construct a context with the related instance and compiled classes with defaults for cacheSizeDefault, cacheExpireDefault and
+     *  maxCompilationRateDefault */
+    public ScriptContext(String name, Class<FactoryType> factoryClazz) {
+        // cache size default, cache expire default, max compilation rate are defaults from ScriptService.
+        this(name, factoryClazz, 100, TimeValue.timeValueMillis(0), new Tuple<>(75, TimeValue.timeValueMinutes(5)));
     }
 
     /** Returns a method with the given name, or throws an exception if multiple are found. */

+ 34 - 20
server/src/main/java/org/elasticsearch/script/ScriptService.java

@@ -46,6 +46,7 @@ import java.io.Closeable;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -241,7 +242,7 @@ public class ScriptService implements Closeable, ClusterStateApplier {
 
         // Validation requires knowing which contexts exist.
         this.validateCacheSettings(settings);
-        cacheHolder = new AtomicReference<>(new CacheHolder(settings, contexts.keySet(), compilationLimitsEnabled()));
+        cacheHolder = new AtomicReference<>(new CacheHolder(settings, contexts.values(), compilationLimitsEnabled()));
     }
 
     /**
@@ -255,12 +256,12 @@ public class ScriptService implements Closeable, ClusterStateApplier {
         clusterSettings.addSettingsUpdateConsumer(SCRIPT_MAX_SIZE_IN_BYTES, this::setMaxSizeInBytes);
 
         // Handle all updatable per-context settings at once for each context.
-        for (String context: contexts.keySet()) {
+        for (ScriptContext<?> context: contexts.values()) {
             clusterSettings.addSettingsUpdateConsumer(
                 (settings) -> cacheHolder.get().updateContextSettings(settings, context),
-                List.of(SCRIPT_CACHE_SIZE_SETTING.getConcreteSettingForNamespace(context),
-                        SCRIPT_CACHE_EXPIRE_SETTING.getConcreteSettingForNamespace(context),
-                        SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace(context),
+                List.of(SCRIPT_CACHE_SIZE_SETTING.getConcreteSettingForNamespace(context.name),
+                        SCRIPT_CACHE_EXPIRE_SETTING.getConcreteSettingForNamespace(context.name),
+                        SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace(context.name),
                         SCRIPT_GENERAL_CACHE_EXPIRE_SETTING, // general settings used for fallbacks
                         SCRIPT_GENERAL_CACHE_SIZE_SETTING
                 )
@@ -580,17 +581,18 @@ public class ScriptService implements Closeable, ClusterStateApplier {
         final ScriptCache general;
         final Map<String, AtomicReference<ScriptCache>> contextCache;
 
-        final Set<String> contexts;
+        final Set<ScriptContext<?>> contexts;
         final boolean compilationLimitsEnabled;
 
-        CacheHolder(Settings settings, Set<String> contexts, boolean compilationLimitsEnabled) {
+        CacheHolder(Settings settings, Collection<ScriptContext<?>> contexts, boolean compilationLimitsEnabled) {
             this.compilationLimitsEnabled = compilationLimitsEnabled;
             this.contexts = Set.copyOf(contexts);
             if (SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.get(settings).equals(USE_CONTEXT_RATE_VALUE)) {
                 this.general = null;
                 Map<String, AtomicReference<ScriptCache>> contextCache = new HashMap<>(this.contexts.size());
-                for (String context : this.contexts) {
-                    contextCache.put(context, new AtomicReference<>(contextFromSettings(settings, context, this.compilationLimitsEnabled)));
+                for (ScriptContext<?> context : this.contexts) {
+                    contextCache.put(context.name,
+                                     new AtomicReference<>(contextFromSettings(settings, context, this.compilationLimitsEnabled)));
                 }
                 this.contextCache = Collections.unmodifiableMap(contextCache);
             } else {
@@ -607,12 +609,24 @@ public class ScriptService implements Closeable, ClusterStateApplier {
         /**
          * Create a ScriptCache for the given context.
          */
-        private static ScriptCache contextFromSettings(Settings settings, String context, boolean compilationLimitsEnabled) {
-            return new ScriptCache(SCRIPT_CACHE_SIZE_SETTING.getConcreteSettingForNamespace(context).get(settings),
-                SCRIPT_CACHE_EXPIRE_SETTING.getConcreteSettingForNamespace(context).get(settings),
-                compilationLimitsEnabled ?
-                    SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace(context).get(settings) :
-                    SCRIPT_COMPILATION_RATE_ZERO);
+        private static ScriptCache contextFromSettings(Settings settings, ScriptContext<?> context, boolean compilationLimitsEnabled) {
+            String name = context.name;
+            Tuple<Integer, TimeValue> compileRate;
+            Setting<Tuple<Integer, TimeValue>> rateSetting = SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace(name);
+            if (compilationLimitsEnabled == false) {
+                compileRate = SCRIPT_COMPILATION_RATE_ZERO;
+            } else if (rateSetting.existsOrFallbackExists(settings)) {
+                compileRate = rateSetting.get(settings);
+            } else {
+                compileRate = context.maxCompilationRateDefault;
+            }
+
+            Setting<TimeValue> cacheExpire = SCRIPT_CACHE_EXPIRE_SETTING.getConcreteSettingForNamespace(name);
+            Setting<Integer> cacheSize = SCRIPT_CACHE_SIZE_SETTING.getConcreteSettingForNamespace(name);
+
+            return new ScriptCache(cacheSize.existsOrFallbackExists(settings) ? cacheSize.get(settings) : context.cacheSizeDefault,
+                                   cacheExpire.existsOrFallbackExists(settings) ? cacheExpire.get(settings) : context.cacheExpireDefault,
+                                   compileRate);
         }
 
         /**
@@ -666,16 +680,16 @@ public class ScriptService implements Closeable, ClusterStateApplier {
         /**
          * Update settings for the context cache, if we're in the context cache mode otherwise no-op.
          */
-        void updateContextSettings(Settings settings, String context) {
+        void updateContextSettings(Settings settings, ScriptContext<?> context) {
             if (general != null) {
                 return;
             }
-            AtomicReference<ScriptCache> ref = contextCache.get(context);
-            assert ref != null : "expected script cache to exist for context [" + context + "]";
+            AtomicReference<ScriptCache> ref = contextCache.get(context.name);
+            assert ref != null : "expected script cache to exist for context [" + context.name + "]";
             ScriptCache cache = ref.get();
-            assert cache != null : "expected script cache to be non-null for context [" + context + "]";
+            assert cache != null : "expected script cache to be non-null for context [" + context.name + "]";
             ref.set(contextFromSettings(settings, context, compilationLimitsEnabled));
-            logger.debug("Replaced context [" + context + "] with new settings");
+            logger.debug("Replaced context [" + context.name + "] with new settings");
         }
     }
 }

+ 110 - 10
server/src/test/java/org/elasticsearch/script/ScriptServiceTests.java

@@ -36,16 +36,24 @@ import org.elasticsearch.test.ESTestCase;
 import org.junit.Before;
 
 import java.io.IOException;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 import static org.elasticsearch.script.ScriptService.MAX_COMPILATION_RATE_FUNCTION;
+import static org.elasticsearch.script.ScriptService.SCRIPT_CACHE_EXPIRE_SETTING;
+import static org.elasticsearch.script.ScriptService.SCRIPT_CACHE_SIZE_SETTING;
+import static org.elasticsearch.script.ScriptService.SCRIPT_GENERAL_CACHE_EXPIRE_SETTING;
+import static org.elasticsearch.script.ScriptService.SCRIPT_GENERAL_CACHE_SIZE_SETTING;
 import static org.elasticsearch.script.ScriptService.SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING;
 import static org.elasticsearch.script.ScriptService.SCRIPT_MAX_COMPILATIONS_RATE_SETTING;
+import static org.elasticsearch.script.ScriptService.USE_CONTEXT_RATE_KEY;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.notNullValue;
@@ -226,7 +234,7 @@ public class ScriptServiceTests extends ESTestCase {
 
     public void testCompilationStatsOnCacheHit() throws IOException {
         Settings.Builder builder = Settings.builder();
-        builder.put(ScriptService.SCRIPT_GENERAL_CACHE_SIZE_SETTING.getKey(), 1);
+        builder.put(SCRIPT_GENERAL_CACHE_SIZE_SETTING.getKey(), 1);
         buildScriptService(builder.build());
         Script script = new Script(ScriptType.INLINE, "test", "1+1", Collections.emptyMap());
         ScriptContext<?> context = randomFrom(contexts.values());
@@ -243,7 +251,7 @@ public class ScriptServiceTests extends ESTestCase {
 
     public void testCacheEvictionCountedInCacheEvictionsStats() throws IOException {
         Settings.Builder builder = Settings.builder();
-        builder.put(ScriptService.SCRIPT_GENERAL_CACHE_SIZE_SETTING.getKey(), 1);
+        builder.put(SCRIPT_GENERAL_CACHE_SIZE_SETTING.getKey(), 1);
         buildScriptService(builder.build());
         scriptService.compile(new Script(ScriptType.INLINE, "test", "1+1", Collections.emptyMap()), randomFrom(contexts.values()));
         scriptService.compile(new Script(ScriptType.INLINE, "test", "2+2", Collections.emptyMap()), randomFrom(contexts.values()));
@@ -361,7 +369,7 @@ public class ScriptServiceTests extends ESTestCase {
         TimeValue cacheExpireFooParsed = TimeValue.parseTimeValue(cacheExpireFoo, "");
 
         Settings s = Settings.builder()
-            .put(ScriptService.SCRIPT_GENERAL_CACHE_SIZE_SETTING.getKey(), cacheSizeBackup)
+            .put(SCRIPT_GENERAL_CACHE_SIZE_SETTING.getKey(), cacheSizeBackup)
             .put(ScriptService.SCRIPT_CACHE_SIZE_SETTING.getConcreteSettingForNamespace("foo").getKey(), cacheSizeFoo)
             .put(ScriptService.SCRIPT_GENERAL_CACHE_EXPIRE_SETTING.getKey(), cacheExpireBackup)
             .put(ScriptService.SCRIPT_CACHE_EXPIRE_SETTING.getConcreteSettingForNamespace("foo").getKey(), cacheExpireFoo)
@@ -396,7 +404,7 @@ public class ScriptServiceTests extends ESTestCase {
         boolean compilationLimitsEnabled = true;
         ScriptService.CacheHolder holder = new ScriptService.CacheHolder(
             Settings.builder().put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), compilationRate).build(),
-            new HashSet<>(Collections.singleton("foo")),
+            Set.of(newContext("foo")),
             compilationLimitsEnabled
         );
 
@@ -407,7 +415,7 @@ public class ScriptServiceTests extends ESTestCase {
         compilationLimitsEnabled = false;
         holder = new ScriptService.CacheHolder(
             Settings.builder().put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), compilationRate).build(),
-            new HashSet<>(Collections.singleton("foo")),
+            new HashSet<>(Collections.singleton(newContext("foo"))),
             compilationLimitsEnabled
         );
 
@@ -426,13 +434,13 @@ public class ScriptServiceTests extends ESTestCase {
             .put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("foo").getKey(), fooCompilationRate)
             .put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("bar").getKey(), barCompilationRate)
             .build();
-        Set<String> contexts = Set.of("foo", "bar", "baz");
+        Collection<ScriptContext<?>> contexts = Set.of(newContext("foo"), newContext("bar"), newContext("baz"));
         ScriptService.CacheHolder holder = new ScriptService.CacheHolder(s, contexts, compilationLimitsEnabled);
 
         assertNull(holder.general);
         assertNotNull(holder.contextCache);
         assertEquals(3, holder.contextCache.size());
-        assertEquals(contexts, holder.contextCache.keySet());
+        assertEquals(contexts.stream().map(c -> c.name).collect(Collectors.toSet()), holder.contextCache.keySet());
 
         assertEquals(ScriptService.MAX_COMPILATION_RATE_FUNCTION.apply(fooCompilationRate), holder.contextCache.get("foo").get().rate);
         assertEquals(ScriptService.MAX_COMPILATION_RATE_FUNCTION.apply(barCompilationRate), holder.contextCache.get("bar").get().rate);
@@ -477,7 +485,8 @@ public class ScriptServiceTests extends ESTestCase {
         Settings s = Settings.builder()
             .put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), compilationRate)
             .build();
-        Set<String> contexts = Set.of("foo", "bar", "baz", "qux");
+        Collection<ScriptContext<?>> contexts = Set.of(newContext("foo"), newContext("bar"), newContext("baz"),
+                                                       newContext("qux"));
         ScriptService.CacheHolder holder = new ScriptService.CacheHolder(s, contexts, true);
 
         assertNotNull(holder.general);
@@ -496,7 +505,7 @@ public class ScriptServiceTests extends ESTestCase {
         assertNull(holder.general);
         assertNotNull(holder.contextCache);
         assertEquals(4, holder.contextCache.size());
-        assertEquals(contexts, holder.contextCache.keySet());
+        assertEquals(contexts.stream().map(c -> c.name).collect(Collectors.toSet()), holder.contextCache.keySet());
 
         assertEquals(ScriptService.MAX_COMPILATION_RATE_FUNCTION.apply(fooCompilationRate), holder.contextCache.get("foo").get().rate);
         assertEquals(ScriptService.MAX_COMPILATION_RATE_FUNCTION.apply(barCompilationRate), holder.contextCache.get("bar").get().rate);
@@ -506,7 +515,7 @@ public class ScriptServiceTests extends ESTestCase {
 
         holder.updateContextSettings(Settings.builder()
                 .put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("bar").getKey(), fooCompilationRate).build(),
-                "bar"
+                newContext("bar")
         );
         assertEquals(ScriptService.MAX_COMPILATION_RATE_FUNCTION.apply(fooCompilationRate), holder.contextCache.get("bar").get().rate);
 
@@ -529,6 +538,93 @@ public class ScriptServiceTests extends ESTestCase {
         assertSame(holder, update);
     }
 
+    public void testFallbackToContextDefaults() {
+        Tuple<Integer, TimeValue> contextDefaultRate = new Tuple<>(randomIntBetween(10, 1024),
+                                                                   TimeValue.timeValueMinutes(randomIntBetween(10, 200)));
+        String name = "foo";
+        ScriptContext<?> foo = new ScriptContext<>(name,
+                                                   ScriptContextTests.DummyScript.Factory.class,
+                                                   randomIntBetween(1, 1024),
+                                                   TimeValue.timeValueMinutes(randomIntBetween(10, 200)),
+                                                   contextDefaultRate);
+
+
+        int generalCacheSize = randomIntBetween(1, 1024);
+        TimeValue generalExpire = TimeValue.timeValueMinutes(randomIntBetween(10, 200));
+
+        String contextRateStr = randomIntBetween(10, 1024) + "/" +  randomIntBetween(10, 200) + "m";
+        Tuple<Integer, TimeValue>  contextRate = MAX_COMPILATION_RATE_FUNCTION.apply(contextRateStr);
+        int contextCacheSize = randomIntBetween(1, 1024);
+        TimeValue contextExpire = TimeValue.timeValueMinutes(randomIntBetween(10, 200));
+
+        // Use context specific
+        ScriptService.CacheHolder contextCache = new ScriptService.CacheHolder(
+            Settings.builder()
+            .put(SCRIPT_CACHE_SIZE_SETTING.getConcreteSettingForNamespace(name).getKey(), contextCacheSize)
+            .put(SCRIPT_CACHE_EXPIRE_SETTING.getConcreteSettingForNamespace(name).getKey(), contextExpire)
+            .put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace(name).getKey(), contextRateStr)
+            .put(SCRIPT_GENERAL_CACHE_SIZE_SETTING.getKey(), generalCacheSize)
+            .put(SCRIPT_GENERAL_CACHE_EXPIRE_SETTING.getKey(), generalExpire)
+            .put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), USE_CONTEXT_RATE_KEY)
+            .build(),
+            List.of(foo),
+            true);
+
+        assertNotNull(contextCache.contextCache);
+        assertNotNull(contextCache.contextCache.get(name));
+        assertNotNull(contextCache.contextCache.get(name).get());
+
+        assertEquals(contextRate, contextCache.contextCache.get(name).get().rate);
+        assertEquals(contextCacheSize, contextCache.contextCache.get(name).get().cacheSize);
+        assertEquals(contextExpire, contextCache.contextCache.get(name).get().cacheExpire);
+
+        // Fallback to general
+        contextCache = new ScriptService.CacheHolder(
+            Settings.builder()
+            .put(SCRIPT_GENERAL_CACHE_SIZE_SETTING.getKey(), generalCacheSize)
+            .put(SCRIPT_GENERAL_CACHE_EXPIRE_SETTING.getKey(), generalExpire)
+            .put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), USE_CONTEXT_RATE_KEY)
+            .build(),
+            List.of(foo),
+            true);
+
+        assertNotNull(contextCache.contextCache);
+        assertNotNull(contextCache.contextCache.get(name));
+        assertNotNull(contextCache.contextCache.get(name).get());
+
+        assertEquals(contextDefaultRate, contextCache.contextCache.get(name).get().rate);
+        assertEquals(generalCacheSize, contextCache.contextCache.get(name).get().cacheSize);
+        assertEquals(generalExpire, contextCache.contextCache.get(name).get().cacheExpire);
+
+        // Fallback to context defaults
+        contextCache = new ScriptService.CacheHolder(
+            Settings.builder()
+            .put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), USE_CONTEXT_RATE_KEY)
+            .build(),
+            List.of(foo),
+            true);
+
+        assertNotNull(contextCache.contextCache);
+        assertNotNull(contextCache.contextCache.get(name));
+        assertNotNull(contextCache.contextCache.get(name).get());
+
+        assertEquals(contextDefaultRate, contextCache.contextCache.get(name).get().rate);
+        assertEquals(foo.cacheSizeDefault, contextCache.contextCache.get(name).get().cacheSize);
+        assertEquals(foo.cacheExpireDefault, contextCache.contextCache.get(name).get().cacheExpire);
+
+        // Use context specific for ingest
+        contextCache = new ScriptService.CacheHolder(
+            Settings.builder()
+                .put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), USE_CONTEXT_RATE_KEY)
+                .build(),
+            List.of(foo, IngestScript.CONTEXT, IngestConditionalScript.CONTEXT),
+            true);
+        assertEquals(new Tuple<>(375, TimeValue.timeValueMinutes(5)),
+                     contextCache.contextCache.get("ingest").get().rate);
+        assertEquals(200, contextCache.contextCache.get("ingest").get().cacheSize);
+        assertEquals(TimeValue.timeValueMillis(0), contextCache.contextCache.get("ingest").get().cacheExpire);
+    }
+
     private void assertCompileRejected(String lang, String script, ScriptType scriptType, ScriptContext scriptContext) {
         try {
             scriptService.compile(new Script(scriptType, lang, script, Collections.emptyMap()), scriptContext);
@@ -545,4 +641,8 @@ public class ScriptServiceTests extends ESTestCase {
                 notNullValue()
         );
     }
+
+    ScriptContext<ScriptContextTests.DummyScript.Factory> newContext(String name) {
+        return new ScriptContext<>(name, ScriptContextTests.DummyScript.Factory.class);
+    }
 }