Make reindex and lang-javascript compatible
Fixes two issues: 1. lang-javascript doesn't support `executable` with a `null` `vars` parameters. The parameter is quite nullable. 2. reindex didn't support script engines who's `unwrap` method wasn't a noop. This didn't come up for lang-groovy or lang-painless because both of those `unwrap`s were noops. lang-javascript copys all maps that it `unwrap`s. This adds fairly low level unit tests for these fixes but dosen't add an integration test that makes sure that reindex and lang-javascript play well together. That'd make backporting this difficult and would add a fairly significant amount of time to the build for a fairly rare interaction. Hopefully the unit tests will be enough.
This commit is contained in:
parent
2904562b01
commit
e07e5d66fa
|
@ -450,6 +450,8 @@ public abstract class AbstractAsyncBulkIndexByScrollAction<Request extends Abstr
|
||||||
}
|
}
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
context = new HashMap<>();
|
context = new HashMap<>();
|
||||||
|
} else {
|
||||||
|
context.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
context.put(IndexFieldMapper.NAME, doc.getIndex());
|
context.put(IndexFieldMapper.NAME, doc.getIndex());
|
||||||
|
@ -485,23 +487,23 @@ public abstract class AbstractAsyncBulkIndexByScrollAction<Request extends Abstr
|
||||||
*/
|
*/
|
||||||
request.setSource((Map<String, Object>) resultCtx.remove(SourceFieldMapper.NAME));
|
request.setSource((Map<String, Object>) resultCtx.remove(SourceFieldMapper.NAME));
|
||||||
|
|
||||||
Object newValue = context.remove(IndexFieldMapper.NAME);
|
Object newValue = resultCtx.remove(IndexFieldMapper.NAME);
|
||||||
if (false == doc.getIndex().equals(newValue)) {
|
if (false == doc.getIndex().equals(newValue)) {
|
||||||
scriptChangedIndex(request, newValue);
|
scriptChangedIndex(request, newValue);
|
||||||
}
|
}
|
||||||
newValue = context.remove(TypeFieldMapper.NAME);
|
newValue = resultCtx.remove(TypeFieldMapper.NAME);
|
||||||
if (false == doc.getType().equals(newValue)) {
|
if (false == doc.getType().equals(newValue)) {
|
||||||
scriptChangedType(request, newValue);
|
scriptChangedType(request, newValue);
|
||||||
}
|
}
|
||||||
newValue = context.remove(IdFieldMapper.NAME);
|
newValue = resultCtx.remove(IdFieldMapper.NAME);
|
||||||
if (false == doc.getId().equals(newValue)) {
|
if (false == doc.getId().equals(newValue)) {
|
||||||
scriptChangedId(request, newValue);
|
scriptChangedId(request, newValue);
|
||||||
}
|
}
|
||||||
newValue = context.remove(VersionFieldMapper.NAME);
|
newValue = resultCtx.remove(VersionFieldMapper.NAME);
|
||||||
if (false == Objects.equals(oldVersion, newValue)) {
|
if (false == Objects.equals(oldVersion, newValue)) {
|
||||||
scriptChangedVersion(request, newValue);
|
scriptChangedVersion(request, newValue);
|
||||||
}
|
}
|
||||||
newValue = context.remove(ParentFieldMapper.NAME);
|
newValue = resultCtx.remove(ParentFieldMapper.NAME);
|
||||||
if (false == Objects.equals(oldParent, newValue)) {
|
if (false == Objects.equals(oldParent, newValue)) {
|
||||||
scriptChangedParent(request, newValue);
|
scriptChangedParent(request, newValue);
|
||||||
}
|
}
|
||||||
|
@ -509,15 +511,15 @@ public abstract class AbstractAsyncBulkIndexByScrollAction<Request extends Abstr
|
||||||
* Its important that routing comes after parent in case you want to
|
* Its important that routing comes after parent in case you want to
|
||||||
* change them both.
|
* change them both.
|
||||||
*/
|
*/
|
||||||
newValue = context.remove(RoutingFieldMapper.NAME);
|
newValue = resultCtx.remove(RoutingFieldMapper.NAME);
|
||||||
if (false == Objects.equals(oldRouting, newValue)) {
|
if (false == Objects.equals(oldRouting, newValue)) {
|
||||||
scriptChangedRouting(request, newValue);
|
scriptChangedRouting(request, newValue);
|
||||||
}
|
}
|
||||||
newValue = context.remove(TimestampFieldMapper.NAME);
|
newValue = resultCtx.remove(TimestampFieldMapper.NAME);
|
||||||
if (false == Objects.equals(oldTimestamp, newValue)) {
|
if (false == Objects.equals(oldTimestamp, newValue)) {
|
||||||
scriptChangedTimestamp(request, newValue);
|
scriptChangedTimestamp(request, newValue);
|
||||||
}
|
}
|
||||||
newValue = context.remove(TTLFieldMapper.NAME);
|
newValue = resultCtx.remove(TTLFieldMapper.NAME);
|
||||||
if (false == Objects.equals(oldTTL, newValue)) {
|
if (false == Objects.equals(oldTTL, newValue)) {
|
||||||
scriptChangedTTL(request, newValue);
|
scriptChangedTTL(request, newValue);
|
||||||
}
|
}
|
||||||
|
@ -527,8 +529,8 @@ public abstract class AbstractAsyncBulkIndexByScrollAction<Request extends Abstr
|
||||||
return scriptChangedOpType(request, oldOpType, newOpType);
|
return scriptChangedOpType(request, oldOpType, newOpType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (false == context.isEmpty()) {
|
if (false == resultCtx.isEmpty()) {
|
||||||
throw new IllegalArgumentException("Invalid fields added to context [" + String.join(",", context.keySet()) + ']');
|
throw new IllegalArgumentException("Invalid fields added to context [" + String.join(",", resultCtx.keySet()) + ']');
|
||||||
}
|
}
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,12 @@ package org.elasticsearch.index.reindex;
|
||||||
|
|
||||||
import org.elasticsearch.script.ExecutableScript;
|
import org.elasticsearch.script.ExecutableScript;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import static org.elasticsearch.test.ESTestCase.randomBoolean;
|
||||||
|
|
||||||
public class SimpleExecutableScript implements ExecutableScript {
|
public class SimpleExecutableScript implements ExecutableScript {
|
||||||
private final Consumer<Map<String, Object>> script;
|
private final Consumer<Map<String, Object>> script;
|
||||||
private Map<String, Object> ctx;
|
private Map<String, Object> ctx;
|
||||||
|
@ -50,6 +53,13 @@ public class SimpleExecutableScript implements ExecutableScript {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object unwrap(Object value) {
|
public Object unwrap(Object value) {
|
||||||
|
// Some script engines (javascript) copy any maps they unwrap
|
||||||
|
if (randomBoolean()) {
|
||||||
|
if (value instanceof Map) {
|
||||||
|
return new HashMap<>((Map<?, ?>) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Others just return the objects plain (groovy, painless)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,15 +172,17 @@ public class JavaScriptScriptEngineService extends AbstractComponent implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> vars) {
|
public ExecutableScript executable(CompiledScript compiledScript, @Nullable Map<String, Object> vars) {
|
||||||
Context ctx = Context.enter();
|
Context ctx = Context.enter();
|
||||||
try {
|
try {
|
||||||
Scriptable scope = ctx.newObject(globalScope);
|
Scriptable scope = ctx.newObject(globalScope);
|
||||||
scope.setPrototype(globalScope);
|
scope.setPrototype(globalScope);
|
||||||
scope.setParentScope(null);
|
scope.setParentScope(null);
|
||||||
|
if (vars != null) {
|
||||||
for (Map.Entry<String, Object> entry : vars.entrySet()) {
|
for (Map.Entry<String, Object> entry : vars.entrySet()) {
|
||||||
ScriptableObject.putProperty(scope, entry.getKey(), entry.getValue());
|
ScriptableObject.putProperty(scope, entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new JavaScriptExecutableScript((Script) compiledScript.compiled(), scope);
|
return new JavaScriptExecutableScript((Script) compiledScript.compiled(), scope);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -25,6 +25,8 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyMap;
|
||||||
|
|
||||||
import org.elasticsearch.common.collect.MapBuilder;
|
import org.elasticsearch.common.collect.MapBuilder;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.script.CompiledScript;
|
import org.elasticsearch.script.CompiledScript;
|
||||||
|
@ -59,6 +61,13 @@ public class JavaScriptScriptEngineTests extends ESTestCase {
|
||||||
assertThat(((Number) o).intValue(), equalTo(3));
|
assertThat(((Number) o).intValue(), equalTo(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testNullVars() {
|
||||||
|
CompiledScript script = new CompiledScript(ScriptService.ScriptType.INLINE, "testSimpleEquation", "js",
|
||||||
|
se.compile(null, "1 + 2", emptyMap()));
|
||||||
|
Object o = se.executable(script, null).run();
|
||||||
|
assertThat(((Number) o).intValue(), equalTo(3));
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void testMapAccess() {
|
public void testMapAccess() {
|
||||||
Map<String, Object> vars = new HashMap<String, Object>();
|
Map<String, Object> vars = new HashMap<String, Object>();
|
||||||
|
|
Loading…
Reference in New Issue