Skip to content

Commit cd9751b

Browse files
committed
Caching script instance instead of script factory
1 parent 4979002 commit cd9751b

File tree

6 files changed

+69
-20
lines changed

6 files changed

+69
-20
lines changed

server/src/main/java/org/elasticsearch/ingest/ConditionalProcessor.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import org.elasticsearch.common.logging.DeprecationCategory;
1313
import org.elasticsearch.common.logging.DeprecationLogger;
14+
import org.elasticsearch.script.CtxMapWrapper;
1415
import org.elasticsearch.script.DynamicMap;
1516
import org.elasticsearch.script.IngestConditionalScript;
1617
import org.elasticsearch.script.Script;
@@ -56,7 +57,8 @@ public class ConditionalProcessor extends AbstractProcessor implements WrappingP
5657
private final Processor processor;
5758
private final IngestMetric metric;
5859
private final LongSupplier relativeTimeProvider;
59-
private final IngestConditionalScript.Factory precompiledConditionScriptFactory;
60+
private final IngestConditionalScript precompiledConditionScript;
61+
private final CtxMapWrapper ctxMapWrapper;
6062

6163
ConditionalProcessor(String tag, String description, Script script, ScriptService scriptService, Processor processor) {
6264
this(tag, description, script, scriptService, processor, System::nanoTime);
@@ -76,12 +78,15 @@ public class ConditionalProcessor extends AbstractProcessor implements WrappingP
7678
this.processor = processor;
7779
this.metric = new IngestMetric();
7880
this.relativeTimeProvider = relativeTimeProvider;
81+
this.ctxMapWrapper = new CtxMapWrapper();
7982

8083
try {
84+
final IngestConditionalScript.Factory factory = scriptService.compile(script, IngestConditionalScript.CONTEXT);
8185
if (ScriptType.INLINE.equals(script.getType())) {
82-
precompiledConditionScriptFactory = scriptService.compile(script, IngestConditionalScript.CONTEXT);
86+
precompiledConditionScript = factory.newInstance(script.getParams(), ctxMapWrapper);
8387
} else {
84-
precompiledConditionScriptFactory = null;
88+
// stored script, so will have to compile at runtime
89+
precompiledConditionScript = null;
8590
}
8691
} catch (ScriptException e) {
8792
throw newConfigurationException(TYPE, tag, null, e);
@@ -139,12 +144,17 @@ public void execute(IngestDocument ingestDocument, BiConsumer<IngestDocument, Ex
139144
}
140145

141146
boolean evaluate(IngestDocument ingestDocument) {
142-
IngestConditionalScript.Factory factory = precompiledConditionScriptFactory;
143-
if (factory == null) {
144-
factory = scriptService.compile(condition, IngestConditionalScript.CONTEXT);
147+
IngestConditionalScript script = precompiledConditionScript;
148+
if (script == null) {
149+
IngestConditionalScript.Factory factory = scriptService.compile(condition, IngestConditionalScript.CONTEXT);
150+
script = factory.newInstance(condition.getParams(), ctxMapWrapper);
151+
}
152+
ctxMapWrapper.setCtxMap(ingestDocument.getCtxMap());
153+
try {
154+
return script.execute(new UnmodifiableIngestData(new DynamicMap(ingestDocument.getSourceAndMetadata(), FUNCTIONS)));
155+
} finally {
156+
ctxMapWrapper.clearCtxMap();
145157
}
146-
return factory.newInstance(condition.getParams(), ingestDocument.getCtxMap())
147-
.execute(new UnmodifiableIngestData(new DynamicMap(ingestDocument.getSourceAndMetadata(), FUNCTIONS)));
148158
}
149159

150160
public Processor getInnerProcessor() {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.script;
11+
12+
/**
13+
* A wrapper for a {@link CtxMap} that allows for ad-hoc setting for script execution.
14+
* This allows for precompilation of scripts that can be executed with different contexts.
15+
* The wrapped {@link CtxMap} should be cleared after use to avoid leaks.
16+
*/
17+
public class CtxMapWrapper {
18+
private volatile CtxMap<?> ctxMap;
19+
20+
public CtxMap<?> getCtxMap() {
21+
if (ctxMap == null) {
22+
throw new IllegalStateException("CtxMap is not set");
23+
}
24+
return ctxMap;
25+
}
26+
27+
public void setCtxMap(CtxMap<?> ctxMap) {
28+
this.ctxMap = ctxMap;
29+
}
30+
31+
public void clearCtxMap() {
32+
this.ctxMap = null;
33+
}
34+
}

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515

1616
/**
1717
* A script used by {@link org.elasticsearch.ingest.ConditionalProcessor}.
18+
* To properly expose the {@link SourceMapFieldScript#field(String)} API, make sure to provide a valid {@link CtxMap} before execution
19+
* through the {@link CtxMapWrapper} passed to the constructor and make sure to clear it after use to avoid leaks.
1820
*/
1921
public abstract class IngestConditionalScript extends SourceMapFieldScript {
2022

21-
public static final String[] PARAMETERS = { "ctxdsf" /*todo change param name*/ };
23+
public static final String[] PARAMETERS = { "runtime-params" };
2224

2325
/** The context used to compile {@link IngestConditionalScript} factories. */
2426
public static final ScriptContext<Factory> CONTEXT = new ScriptContext<>(
@@ -33,8 +35,8 @@ public abstract class IngestConditionalScript extends SourceMapFieldScript {
3335
/** The generic runtime parameters for the script. */
3436
private final Map<String, Object> params;
3537

36-
public IngestConditionalScript(Map<String, Object> params, CtxMap<?> ctxMap) {
37-
super(ctxMap);
38+
public IngestConditionalScript(Map<String, Object> params, CtxMapWrapper ctxMapWrapper) {
39+
super(ctxMapWrapper);
3840
this.params = params;
3941
}
4042

@@ -46,6 +48,6 @@ public Map<String, Object> getParams() {
4648
public abstract boolean execute(Map<String, Object> params);
4749

4850
public interface Factory {
49-
IngestConditionalScript newInstance(Map<String, Object> params, CtxMap<?> ctxMap);
51+
IngestConditionalScript newInstance(Map<String, Object> params, CtxMapWrapper ctxMapWrapper);
5052
}
5153
}

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,23 @@
1818
* These scripts provide {@code ctx} for backwards compatibility and expose {@link Metadata}.
1919
*/
2020
public abstract class SourceMapFieldScript {
21-
protected final CtxMap<?> ctxMap;
21+
protected final CtxMapWrapper ctxMapWrapper;
2222

23-
public SourceMapFieldScript(CtxMap<?> ctxMap) {
24-
this.ctxMap = ctxMap;
23+
public SourceMapFieldScript(CtxMapWrapper ctxMapWrapper) {
24+
this.ctxMapWrapper = ctxMapWrapper;
2525
}
2626

2727
/** Provides backwards compatibility access to ctx */
2828
public Map<String, Object> getCtx() {
29-
return ctxMap;
29+
return ctxMapWrapper.getCtxMap();
3030
}
3131

3232
/** Return the metadata for this script */
3333
public Metadata metadata() {
34-
return ctxMap.getMetadata();
34+
return ctxMapWrapper.getCtxMap().getMetadata();
3535
}
3636

3737
public SourceMapField field(String path) {
38-
return new SourceMapField(path, ctxMap::getSource);
38+
return new SourceMapField(path, () -> ctxMapWrapper.getCtxMap().getSource());
3939
}
4040
}

server/src/test/java/org/elasticsearch/ingest/ConditionalProcessorTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public boolean execute(Map<String, Object> params) {
226226
public void testRuntimeError() {
227227
ScriptService scriptService = MockScriptService.singleContext(
228228
IngestConditionalScript.CONTEXT,
229-
code -> (params, ctxMap) -> new IngestConditionalScript(params, ctxMap) {
229+
code -> (params, ctxMapWrapper) -> new IngestConditionalScript(params, ctxMapWrapper) {
230230
@Override
231231
public boolean execute(Map<String, Object> params) {
232232
throw new IllegalArgumentException("runtime problem");

test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,10 @@ public void execute() {
169169
} else if (context.instanceClazz.equals(AggregationScript.class)) {
170170
return context.factoryClazz.cast(new MockAggregationScript(script));
171171
} else if (context.instanceClazz.equals(IngestConditionalScript.class)) {
172-
IngestConditionalScript.Factory factory = (parameters, ctxMap) -> new IngestConditionalScript(parameters, ctxMap) {
172+
IngestConditionalScript.Factory factory = (parameters, ctxMapWrapper) -> new IngestConditionalScript(
173+
parameters,
174+
ctxMapWrapper
175+
) {
173176
@Override
174177
public boolean execute(Map<String, Object> params) {
175178
return (boolean) script.apply(params);

0 commit comments

Comments
 (0)