Skip to content

Commit f8d4b0c

Browse files
authored
Scripting: Context script cache unlimited compile (#53769)
* Adds "unlimited" compilation rate for context script caches * `script.context.${CONTEXT}.max_compilations_rate` = `unlimited` disables compilation rate limiting for `${CONTEXT}`'s script cache Refs: #50152
1 parent f324394 commit f8d4b0c

File tree

4 files changed

+49
-8
lines changed

4 files changed

+49
-8
lines changed

server/src/main/java/org/elasticsearch/script/ScriptCache.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,16 @@ public class ScriptCache {
4040

4141
private static final Logger logger = LogManager.getLogger(ScriptService.class);
4242

43+
static final Tuple<Integer, TimeValue> UNLIMITED_COMPILATION_RATE = new Tuple<>(0, TimeValue.ZERO);
44+
4345
private final Cache<CacheKey, Object> cache;
4446
private final ScriptMetrics scriptMetrics;
4547

4648
private final Object lock = new Object();
4749

48-
// Mutable fields
49-
private long lastInlineCompileTime;
50-
private double scriptsPerTimeWindow;
50+
// Mutable fields, visible for tests
51+
long lastInlineCompileTime;
52+
double scriptsPerTimeWindow;
5153

5254
// Cache settings or derived from settings
5355
final int cacheSize;
@@ -150,8 +152,7 @@ public ScriptStats stats() {
150152
* is discarded - there can never be more water in the bucket than the size of the bucket.
151153
*/
152154
void checkCompilationLimit() {
153-
if (rate.v1() == 0 && rate.v2().getNanos() == 0) {
154-
// unlimited
155+
if (rate.equals(UNLIMITED_COMPILATION_RATE)) {
155156
return;
156157
}
157158

server/src/main/java/org/elasticsearch/script/ScriptService.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,16 @@ public class ScriptService implements Closeable, ClusterStateApplier {
128128
key -> Setting.positiveTimeSetting(key, SCRIPT_GENERAL_CACHE_EXPIRE_SETTING, TimeValue.timeValueMillis(0),
129129
Property.NodeScope, Property.Dynamic));
130130

131+
// Unlimited compilation rate for context-specific script caches
132+
static final String UNLIMITED_COMPILATION_RATE_KEY = "unlimited";
133+
131134
public static final Setting.AffixSetting<Tuple<Integer, TimeValue>> SCRIPT_MAX_COMPILATIONS_RATE_SETTING =
132135
Setting.affixKeySetting(CONTEXT_PREFIX,
133136
"max_compilations_rate",
134-
key -> new Setting<>(key, "75/5m", MAX_COMPILATION_RATE_FUNCTION, Property.NodeScope, Property.Dynamic));
137+
key -> new Setting<>(key, "75/5m",
138+
(String value) -> value.equals(UNLIMITED_COMPILATION_RATE_KEY) ? ScriptCache.UNLIMITED_COMPILATION_RATE:
139+
MAX_COMPILATION_RATE_FUNCTION.apply(value),
140+
Property.NodeScope, Property.Dynamic));
135141

136142
private static final Tuple<Integer, TimeValue> SCRIPT_COMPILATION_RATE_ZERO = new Tuple<>(0, TimeValue.ZERO);
137143

server/src/test/java/org/elasticsearch/script/ScriptCacheTests.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,17 @@ public void testCompilationCircuitBreaking() throws Exception {
5252
cache.checkCompilationLimit();
5353
}
5454
}
55+
56+
public void testUnlimitedCompilationRate() {
57+
final Integer size = ScriptService.SCRIPT_GENERAL_CACHE_SIZE_SETTING.get(Settings.EMPTY);
58+
final TimeValue expire = ScriptService.SCRIPT_GENERAL_CACHE_EXPIRE_SETTING.get(Settings.EMPTY);
59+
ScriptCache cache = new ScriptCache(size, expire, ScriptCache.UNLIMITED_COMPILATION_RATE);
60+
long lastInlineCompileTime = cache.lastInlineCompileTime;
61+
double scriptsPerTimeWindow = cache.scriptsPerTimeWindow;
62+
for(int i=0; i < 3000; i++) {
63+
cache.checkCompilationLimit();
64+
assertEquals(lastInlineCompileTime, cache.lastInlineCompileTime);
65+
assertEquals(scriptsPerTimeWindow, cache.scriptsPerTimeWindow, 0.0); // delta of 0.0 because it should never change
66+
}
67+
}
5568
}

server/src/test/java/org/elasticsearch/script/ScriptServiceTests.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,24 @@ public void testCacheHolderContextConstructor() {
450450
assertEquals(zero, holder.contextCache.get("baz").get().rate);
451451
}
452452

453+
public void testCompilationRateUnlimitedContextOnly() throws IOException {
454+
IllegalArgumentException illegal = expectThrows(IllegalArgumentException.class, () -> {
455+
buildScriptService(Settings.builder()
456+
.put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), ScriptService.UNLIMITED_COMPILATION_RATE_KEY)
457+
.build());
458+
});
459+
assertEquals("parameter must contain a positive integer and a timevalue, i.e. 10/1m, but was [unlimited]", illegal.getMessage());
460+
461+
// Should not throw.
462+
buildScriptService(Settings.builder()
463+
.put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("ingest").getKey(),
464+
ScriptService.UNLIMITED_COMPILATION_RATE_KEY)
465+
.put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("field").getKey(),
466+
ScriptService.UNLIMITED_COMPILATION_RATE_KEY)
467+
.put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), ScriptService.USE_CONTEXT_RATE_KEY)
468+
.build());
469+
}
470+
453471
public void testCacheHolderChangeSettings() {
454472
String fooCompilationRate = "77/5m";
455473
String barCompilationRate = "78/6m";
@@ -459,7 +477,7 @@ public void testCacheHolderChangeSettings() {
459477
Settings s = Settings.builder()
460478
.put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), compilationRate)
461479
.build();
462-
Set<String> contexts = Set.of("foo", "bar", "baz");
480+
Set<String> contexts = Set.of("foo", "bar", "baz", "qux");
463481
ScriptService.CacheHolder holder = new ScriptService.CacheHolder(s, contexts, true);
464482

465483
assertNotNull(holder.general);
@@ -470,16 +488,19 @@ public void testCacheHolderChangeSettings() {
470488
.put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), ScriptService.USE_CONTEXT_RATE_KEY)
471489
.put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("foo").getKey(), fooCompilationRate)
472490
.put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("bar").getKey(), barCompilationRate)
491+
.put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("qux").getKey(),
492+
ScriptService.UNLIMITED_COMPILATION_RATE_KEY)
473493
.build()
474494
);
475495

476496
assertNull(holder.general);
477497
assertNotNull(holder.contextCache);
478-
assertEquals(3, holder.contextCache.size());
498+
assertEquals(4, holder.contextCache.size());
479499
assertEquals(contexts, holder.contextCache.keySet());
480500

481501
assertEquals(ScriptService.MAX_COMPILATION_RATE_FUNCTION.apply(fooCompilationRate), holder.contextCache.get("foo").get().rate);
482502
assertEquals(ScriptService.MAX_COMPILATION_RATE_FUNCTION.apply(barCompilationRate), holder.contextCache.get("bar").get().rate);
503+
assertEquals(ScriptCache.UNLIMITED_COMPILATION_RATE, holder.contextCache.get("qux").get().rate);
483504
assertEquals(ScriptService.SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getDefault(Settings.EMPTY),
484505
holder.contextCache.get("baz").get().rate);
485506

0 commit comments

Comments
 (0)