* 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
This commit is contained in:
parent
1f3de2fa7e
commit
ac575b68a9
|
@ -40,14 +40,16 @@ public class ScriptCache {
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger(ScriptService.class);
|
private static final Logger logger = LogManager.getLogger(ScriptService.class);
|
||||||
|
|
||||||
|
static final Tuple<Integer, TimeValue> UNLIMITED_COMPILATION_RATE = new Tuple<>(0, TimeValue.ZERO);
|
||||||
|
|
||||||
private final Cache<CacheKey, Object> cache;
|
private final Cache<CacheKey, Object> cache;
|
||||||
private final ScriptMetrics scriptMetrics;
|
private final ScriptMetrics scriptMetrics;
|
||||||
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
|
|
||||||
// Mutable fields
|
// Mutable fields, visible for tests
|
||||||
private long lastInlineCompileTime;
|
long lastInlineCompileTime;
|
||||||
private double scriptsPerTimeWindow;
|
double scriptsPerTimeWindow;
|
||||||
|
|
||||||
// Cache settings or derived from settings
|
// Cache settings or derived from settings
|
||||||
final int cacheSize;
|
final int cacheSize;
|
||||||
|
@ -150,8 +152,7 @@ public class ScriptCache {
|
||||||
* is discarded - there can never be more water in the bucket than the size of the bucket.
|
* is discarded - there can never be more water in the bucket than the size of the bucket.
|
||||||
*/
|
*/
|
||||||
void checkCompilationLimit() {
|
void checkCompilationLimit() {
|
||||||
if (rate.v1() == 0 && rate.v2().getNanos() == 0) {
|
if (rate.equals(UNLIMITED_COMPILATION_RATE)) {
|
||||||
// unlimited
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,10 +129,16 @@ public class ScriptService implements Closeable, ClusterStateApplier {
|
||||||
key -> Setting.positiveTimeSetting(key, SCRIPT_GENERAL_CACHE_EXPIRE_SETTING, TimeValue.timeValueMillis(0),
|
key -> Setting.positiveTimeSetting(key, SCRIPT_GENERAL_CACHE_EXPIRE_SETTING, TimeValue.timeValueMillis(0),
|
||||||
Property.NodeScope, Property.Dynamic));
|
Property.NodeScope, Property.Dynamic));
|
||||||
|
|
||||||
|
// Unlimited compilation rate for context-specific script caches
|
||||||
|
static final String UNLIMITED_COMPILATION_RATE_KEY = "unlimited";
|
||||||
|
|
||||||
public static final Setting.AffixSetting<Tuple<Integer, TimeValue>> SCRIPT_MAX_COMPILATIONS_RATE_SETTING =
|
public static final Setting.AffixSetting<Tuple<Integer, TimeValue>> SCRIPT_MAX_COMPILATIONS_RATE_SETTING =
|
||||||
Setting.affixKeySetting(CONTEXT_PREFIX,
|
Setting.affixKeySetting(CONTEXT_PREFIX,
|
||||||
"max_compilations_rate",
|
"max_compilations_rate",
|
||||||
key -> new Setting<>(key, "75/5m", MAX_COMPILATION_RATE_FUNCTION, Property.NodeScope, Property.Dynamic));
|
key -> new Setting<>(key, "75/5m",
|
||||||
|
(String value) -> value.equals(UNLIMITED_COMPILATION_RATE_KEY) ? ScriptCache.UNLIMITED_COMPILATION_RATE:
|
||||||
|
MAX_COMPILATION_RATE_FUNCTION.apply(value),
|
||||||
|
Property.NodeScope, Property.Dynamic));
|
||||||
|
|
||||||
private static final Tuple<Integer, TimeValue> SCRIPT_COMPILATION_RATE_ZERO = new Tuple<>(0, TimeValue.ZERO);
|
private static final Tuple<Integer, TimeValue> SCRIPT_COMPILATION_RATE_ZERO = new Tuple<>(0, TimeValue.ZERO);
|
||||||
|
|
||||||
|
|
|
@ -52,4 +52,17 @@ public class ScriptCacheTests extends ESTestCase {
|
||||||
cache.checkCompilationLimit();
|
cache.checkCompilationLimit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testUnlimitedCompilationRate() {
|
||||||
|
final Integer size = ScriptService.SCRIPT_GENERAL_CACHE_SIZE_SETTING.get(Settings.EMPTY);
|
||||||
|
final TimeValue expire = ScriptService.SCRIPT_GENERAL_CACHE_EXPIRE_SETTING.get(Settings.EMPTY);
|
||||||
|
ScriptCache cache = new ScriptCache(size, expire, ScriptCache.UNLIMITED_COMPILATION_RATE);
|
||||||
|
long lastInlineCompileTime = cache.lastInlineCompileTime;
|
||||||
|
double scriptsPerTimeWindow = cache.scriptsPerTimeWindow;
|
||||||
|
for(int i=0; i < 3000; i++) {
|
||||||
|
cache.checkCompilationLimit();
|
||||||
|
assertEquals(lastInlineCompileTime, cache.lastInlineCompileTime);
|
||||||
|
assertEquals(scriptsPerTimeWindow, cache.scriptsPerTimeWindow, 0.0); // delta of 0.0 because it should never change
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -451,6 +451,24 @@ public class ScriptServiceTests extends ESTestCase {
|
||||||
assertEquals(zero, holder.contextCache.get("baz").get().rate);
|
assertEquals(zero, holder.contextCache.get("baz").get().rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testCompilationRateUnlimitedContextOnly() throws IOException {
|
||||||
|
IllegalArgumentException illegal = expectThrows(IllegalArgumentException.class, () -> {
|
||||||
|
buildScriptService(Settings.builder()
|
||||||
|
.put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), ScriptService.UNLIMITED_COMPILATION_RATE_KEY)
|
||||||
|
.build());
|
||||||
|
});
|
||||||
|
assertEquals("parameter must contain a positive integer and a timevalue, i.e. 10/1m, but was [unlimited]", illegal.getMessage());
|
||||||
|
|
||||||
|
// Should not throw.
|
||||||
|
buildScriptService(Settings.builder()
|
||||||
|
.put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("ingest").getKey(),
|
||||||
|
ScriptService.UNLIMITED_COMPILATION_RATE_KEY)
|
||||||
|
.put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("field").getKey(),
|
||||||
|
ScriptService.UNLIMITED_COMPILATION_RATE_KEY)
|
||||||
|
.put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), ScriptService.USE_CONTEXT_RATE_KEY)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
public void testCacheHolderChangeSettings() {
|
public void testCacheHolderChangeSettings() {
|
||||||
String fooCompilationRate = "77/5m";
|
String fooCompilationRate = "77/5m";
|
||||||
String barCompilationRate = "78/6m";
|
String barCompilationRate = "78/6m";
|
||||||
|
@ -460,7 +478,7 @@ public class ScriptServiceTests extends ESTestCase {
|
||||||
Settings s = Settings.builder()
|
Settings s = Settings.builder()
|
||||||
.put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), compilationRate)
|
.put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), compilationRate)
|
||||||
.build();
|
.build();
|
||||||
Set<String> contexts = new HashSet<>(Arrays.asList("foo", "bar", "baz"));
|
Set<String> contexts = new HashSet<>(Arrays.asList("foo", "bar", "baz", "qux"));
|
||||||
ScriptService.CacheHolder holder = new ScriptService.CacheHolder(s, contexts, true);
|
ScriptService.CacheHolder holder = new ScriptService.CacheHolder(s, contexts, true);
|
||||||
|
|
||||||
assertNotNull(holder.general);
|
assertNotNull(holder.general);
|
||||||
|
@ -471,16 +489,19 @@ public class ScriptServiceTests extends ESTestCase {
|
||||||
.put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), ScriptService.USE_CONTEXT_RATE_KEY)
|
.put(SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING.getKey(), ScriptService.USE_CONTEXT_RATE_KEY)
|
||||||
.put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("foo").getKey(), fooCompilationRate)
|
.put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("foo").getKey(), fooCompilationRate)
|
||||||
.put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("bar").getKey(), barCompilationRate)
|
.put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("bar").getKey(), barCompilationRate)
|
||||||
|
.put(SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getConcreteSettingForNamespace("qux").getKey(),
|
||||||
|
ScriptService.UNLIMITED_COMPILATION_RATE_KEY)
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
|
||||||
assertNull(holder.general);
|
assertNull(holder.general);
|
||||||
assertNotNull(holder.contextCache);
|
assertNotNull(holder.contextCache);
|
||||||
assertEquals(3, holder.contextCache.size());
|
assertEquals(4, holder.contextCache.size());
|
||||||
assertEquals(contexts, holder.contextCache.keySet());
|
assertEquals(contexts, holder.contextCache.keySet());
|
||||||
|
|
||||||
assertEquals(ScriptService.MAX_COMPILATION_RATE_FUNCTION.apply(fooCompilationRate), holder.contextCache.get("foo").get().rate);
|
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);
|
assertEquals(ScriptService.MAX_COMPILATION_RATE_FUNCTION.apply(barCompilationRate), holder.contextCache.get("bar").get().rate);
|
||||||
|
assertEquals(ScriptCache.UNLIMITED_COMPILATION_RATE, holder.contextCache.get("qux").get().rate);
|
||||||
assertEquals(ScriptService.SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getDefault(Settings.EMPTY),
|
assertEquals(ScriptService.SCRIPT_MAX_COMPILATIONS_RATE_SETTING.getDefault(Settings.EMPTY),
|
||||||
holder.contextCache.get("baz").get().rate);
|
holder.contextCache.get("baz").get().rate);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue