Skip to content

Commit

Permalink
Scripting: Per-context script cache, default off (#52855)
Browse files Browse the repository at this point in the history
* Adds per context settings:
  `script.context.${CONTEXT}.cache_max_size` ~
  `script.cache.max_size`

  `script.context.${CONTEXT}.cache_expire` ~
  `script.cache.expire`

  `script.context.${CONTEXT}.max_compilations_rate` ~
  `script.max_compilations_rate`

* Context cache is used if:
  `script.max_compilations_rate=use-context`.  This
  value is dynamically updatable, so users can
  switch back to the general cache if desired.

* Settings for context caches take the first value 
  that applies:
  1) Context specific settings if set, eg
     `script.context.ingest.cache_max_size`
  2) Correlated general setting is set to the non-default 
     value, eg `script.cache.max_size`
  3) Context default

The reason for 2's inclusion is to allow an easy
transition for users who've customized their general
cache settings.

Using the general cache settings for the context caches
results in higher effective settings, since they are 
multiplied across the number of contexts.  So a general
cache max size of 200 will become 200 * # of contexts.
However, this behavior it will avoid users snapping to a
value that is too low for them.


Refs: #50152
  • Loading branch information
stu-elastic authored Mar 18, 2020
1 parent c46e0f5 commit 070ea7e
Show file tree
Hide file tree
Showing 12 changed files with 544 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ public synchronized void addSettingsUpdateConsumer(Consumer<Settings> consumer,
addSettingsUpdater(Setting.groupedSettingsUpdater(consumer, settings));
}

/**
* Adds a settings consumer that is only executed if any setting in the supplied list of settings is changed. In that case all the
* settings are specified in the argument are returned. The validator is run across all specified settings before the settings are
* applied.
*
* Also automatically adds empty consumers for all settings in order to activate logging
*/
public synchronized void addSettingsUpdateConsumer(Consumer<Settings> consumer, List<? extends Setting<?>> settings,
Consumer<Settings> validator) {
addSettingsUpdater(Setting.groupedSettingsUpdater(consumer, settings, validator));
}

/**
* Adds a settings consumer for affix settings. Affix settings have a namespace associated to it that needs to be available to the
* consumer in order to be processed correctly.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,10 +364,13 @@ public void apply(Settings value, Settings current, Settings previous) {
NetworkService.TCP_RECEIVE_BUFFER_SIZE,
IndexSettings.QUERY_STRING_ANALYZE_WILDCARD,
IndexSettings.QUERY_STRING_ALLOW_LEADING_WILDCARD,
ScriptService.SCRIPT_GENERAL_CACHE_SIZE_SETTING,
ScriptService.SCRIPT_GENERAL_CACHE_EXPIRE_SETTING,
ScriptService.SCRIPT_GENERAL_MAX_COMPILATIONS_RATE_SETTING,
ScriptService.SCRIPT_CACHE_SIZE_SETTING,
ScriptService.SCRIPT_CACHE_EXPIRE_SETTING,
ScriptService.SCRIPT_MAX_COMPILATIONS_RATE_SETTING,
ScriptService.SCRIPT_MAX_SIZE_IN_BYTES,
ScriptService.SCRIPT_MAX_COMPILATIONS_RATE,
ScriptService.TYPES_ALLOWED_SETTING,
ScriptService.CONTEXTS_ALLOWED_SETTING,
IndicesService.INDICES_CACHE_CLEAN_INTERVAL_SETTING,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,12 @@ public String toString() {

static AbstractScopedSettings.SettingUpdater<Settings> groupedSettingsUpdater(Consumer<Settings> consumer,
final List<? extends Setting<?>> configuredSettings) {
return groupedSettingsUpdater(consumer, configuredSettings, (v) -> {});
}

static AbstractScopedSettings.SettingUpdater<Settings> groupedSettingsUpdater(Consumer<Settings> consumer,
final List<? extends Setting<?>> configuredSettings,
Consumer<Settings> validator) {
return new AbstractScopedSettings.SettingUpdater<Settings>() {

private Settings get(Settings settings) {
Expand All @@ -691,6 +696,7 @@ public boolean hasChanged(Settings current, Settings previous) {

@Override
public Settings getValue(Settings current, Settings previous) {
validator.accept(current);
return get(current);
}

Expand Down
66 changes: 22 additions & 44 deletions server/src/main/java/org/elasticsearch/script/ScriptCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,53 +40,47 @@ public class ScriptCache {

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

private Cache<CacheKey, Object> cache;
private final ScriptMetrics scriptMetrics = new ScriptMetrics();
private final Cache<CacheKey, Object> cache;
private final ScriptMetrics scriptMetrics;

private final Object lock = new Object();

private Tuple<Integer, TimeValue> rate;
// Mutable fields
private long lastInlineCompileTime;
private double scriptsPerTimeWindow;
private double compilesAllowedPerNano;

// Cache settings
private int cacheSize;
private TimeValue cacheExpire;
// Cache settings or derived from settings
final int cacheSize;
final TimeValue cacheExpire;
final Tuple<Integer, TimeValue> rate;
private final double compilesAllowedPerNano;

public ScriptCache(
ScriptCache(
int cacheMaxSize,
TimeValue cacheExpire,
Tuple<Integer, TimeValue> maxCompilationRate
) {
this.cacheSize = cacheMaxSize;
this.cacheExpire = cacheExpire;

CacheBuilder<CacheKey, Object> cacheBuilder = CacheBuilder.builder();
if (cacheMaxSize >= 0) {
cacheBuilder.setMaximumWeight(cacheMaxSize);
if (this.cacheSize >= 0) {
cacheBuilder.setMaximumWeight(this.cacheSize);
}

if (cacheExpire.getNanos() != 0) {
cacheBuilder.setExpireAfterAccess(cacheExpire);
if (this.cacheExpire.getNanos() != 0) {
cacheBuilder.setExpireAfterAccess(this.cacheExpire);
}

logger.debug("using script cache with max_size [{}], expire [{}]", cacheMaxSize, cacheExpire);
logger.debug("using script cache with max_size [{}], expire [{}]", this.cacheSize, this.cacheExpire);
this.cache = cacheBuilder.removalListener(new ScriptCacheRemovalListener()).build();

this.lastInlineCompileTime = System.nanoTime();

this.cacheSize = cacheMaxSize;
this.cacheExpire = cacheExpire;
this.setMaxCompilationRate(maxCompilationRate);
}
this.rate = maxCompilationRate;
this.scriptsPerTimeWindow = this.rate.v1();
this.compilesAllowedPerNano = ((double) rate.v1()) / rate.v2().nanos();

private Cache<CacheKey,Object> buildCache() {
CacheBuilder<CacheKey, Object> cacheBuilder = CacheBuilder.builder();
if (cacheSize >= 0) {
cacheBuilder.setMaximumWeight(cacheSize);
}
if (cacheExpire.getNanos() != 0) {
cacheBuilder.setExpireAfterAccess(cacheExpire);
}
return cacheBuilder.removalListener(new ScriptCacheRemovalListener()).build();
this.lastInlineCompileTime = System.nanoTime();
this.scriptMetrics = new ScriptMetrics();
}

<FactoryType> FactoryType compile(
Expand Down Expand Up @@ -185,22 +179,6 @@ void checkCompilationLimit() {
}
}

/**
* This configures the maximum script compilations per five minute window.
*
* @param newRate the new expected maximum number of compilations per five minute window
*/
void setMaxCompilationRate(Tuple<Integer, TimeValue> newRate) {
synchronized (lock) {
this.rate = newRate;
// Reset the counter to allow new compilations
this.scriptsPerTimeWindow = rate.v1();
this.compilesAllowedPerNano = ((double) rate.v1()) / newRate.v2().nanos();

this.cache = buildCache();
}
}

/**
* A small listener for the script cache that calls each
* {@code ScriptEngine}'s {@code scriptRemoved} method when the
Expand Down
Loading

0 comments on commit 070ea7e

Please sign in to comment.