diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index a5a9b4209ba..cbb97179a46 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -84,7 +84,7 @@ dependencies { compile 'com.netflix.nebula:gradle-info-plugin:3.0.3' compile 'org.eclipse.jgit:org.eclipse.jgit:3.2.0.201312181205-r' compile 'com.perforce:p4java:2012.3.551082' // THIS IS SUPPOSED TO BE OPTIONAL IN THE FUTURE.... - compile 'de.thetaphi:forbiddenapis:2.1' + compile 'de.thetaphi:forbiddenapis:2.2' compile 'com.bmuschko:gradle-nexus-plugin:2.3.1' compile 'org.apache.rat:apache-rat:0.11' } diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/doc/RestTestsFromSnippetsTask.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/doc/RestTestsFromSnippetsTask.groovy index c9f5668a326..ba7311fee6f 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/doc/RestTestsFromSnippetsTask.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/doc/RestTestsFromSnippetsTask.groovy @@ -127,7 +127,7 @@ public class RestTestsFromSnippetsTask extends SnippetsTask { current.println(setup) } - body(test) + body(test, false) } private void response(Snippet response) { @@ -136,7 +136,7 @@ public class RestTestsFromSnippetsTask extends SnippetsTask { } void emitDo(String method, String pathAndQuery, - String body, String catchPart) { + String body, String catchPart, boolean inSetup) { def (String path, String query) = pathAndQuery.tokenize('?') current.println(" - do:") if (catchPart != null) { @@ -160,6 +160,19 @@ public class RestTestsFromSnippetsTask extends SnippetsTask { current.println(" body: |") body.eachLine { current.println(" $it") } } + /* Catch any shard failures. These only cause a non-200 response if + * no shard succeeds. But we need to fail the tests on all of these + * because they mean invalid syntax or broken queries or something + * else that we don't want to teach people to do. The REST test + * framework doesn't allow us to has assertions in the setup + * section so we have to skip it there. We also have to skip _cat + * actions because they don't return json so we can't is_false + * them. That is ok because they don't have this + * partial-success-is-success thing. + */ + if (false == inSetup && false == path.startsWith('_cat')) { + current.println(" - is_false: _shards.failures") + } } private void setup(Snippet setup) { @@ -169,7 +182,7 @@ public class RestTestsFromSnippetsTask extends SnippetsTask { setupCurrent(setup) current.println('---') current.println("setup:") - body(setup) + body(setup, true) // always wait for yellow before anything is executed current.println( " - do:\n" + @@ -179,7 +192,7 @@ public class RestTestsFromSnippetsTask extends SnippetsTask { " wait_for_status: \"yellow\"") } - private void body(Snippet snippet) { + private void body(Snippet snippet, boolean inSetup) { parse("$snippet", snippet.contents, SYNTAX) { matcher, last -> if (matcher.group("comment") != null) { // Comment @@ -193,7 +206,7 @@ public class RestTestsFromSnippetsTask extends SnippetsTask { // Leading '/'s break the generated paths pathAndQuery = pathAndQuery.substring(1) } - emitDo(method, pathAndQuery, body, catchPart) + emitDo(method, pathAndQuery, body, catchPart, inSetup) } } diff --git a/buildSrc/src/main/resources/checkstyle_suppressions.xml b/buildSrc/src/main/resources/checkstyle_suppressions.xml index 94494a06542..27b9efbf0a4 100644 --- a/buildSrc/src/main/resources/checkstyle_suppressions.xml +++ b/buildSrc/src/main/resources/checkstyle_suppressions.xml @@ -712,7 +712,6 @@ - @@ -859,7 +858,6 @@ - @@ -1023,7 +1021,6 @@ - diff --git a/buildSrc/src/main/resources/forbidden/es-all-signatures.txt b/buildSrc/src/main/resources/forbidden/es-all-signatures.txt index 71eb1433521..37f03f4c91c 100644 --- a/buildSrc/src/main/resources/forbidden/es-all-signatures.txt +++ b/buildSrc/src/main/resources/forbidden/es-all-signatures.txt @@ -32,7 +32,7 @@ org.apache.lucene.index.IndexReader#getCombinedCoreAndDeletesKey() @defaultMessage Soon to be removed org.apache.lucene.document.FieldType#numericType() -@defaultMessage Don't use MethodHandles in slow ways, dont be lenient in tests. -# unfortunately, invoke() cannot be banned, because forbidden apis does not support signature polymorphic methods +@defaultMessage Don't use MethodHandles in slow ways, don't be lenient in tests. +java.lang.invoke.MethodHandle#invoke(java.lang.Object[]) java.lang.invoke.MethodHandle#invokeWithArguments(java.lang.Object[]) java.lang.invoke.MethodHandle#invokeWithArguments(java.util.List) diff --git a/core/src/main/java/org/elasticsearch/Version.java b/core/src/main/java/org/elasticsearch/Version.java index e77b0f450dd..7e2ffd1dfa0 100644 --- a/core/src/main/java/org/elasticsearch/Version.java +++ b/core/src/main/java/org/elasticsearch/Version.java @@ -22,7 +22,6 @@ package org.elasticsearch; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.Strings; import org.elasticsearch.common.SuppressForbidden; -import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; @@ -329,18 +328,4 @@ public class Version { public boolean isRC() { return build > 50 && build < 99; } - - public static class Module extends AbstractModule { - - private final Version version; - - public Module(Version version) { - this.version = version; - } - - @Override - protected void configure() { - bind(Version.class).toInstance(version); - } - } } diff --git a/core/src/main/java/org/elasticsearch/action/main/TransportMainAction.java b/core/src/main/java/org/elasticsearch/action/main/TransportMainAction.java index 6bf60835490..c37268a52de 100644 --- a/core/src/main/java/org/elasticsearch/action/main/TransportMainAction.java +++ b/core/src/main/java/org/elasticsearch/action/main/TransportMainAction.java @@ -37,15 +37,13 @@ import org.elasticsearch.transport.TransportService; public class TransportMainAction extends HandledTransportAction { private final ClusterService clusterService; - private final Version version; @Inject public TransportMainAction(Settings settings, ThreadPool threadPool, TransportService transportService, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - ClusterService clusterService, Version version) { + ClusterService clusterService) { super(settings, MainAction.NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, MainRequest::new); this.clusterService = clusterService; - this.version = version; } @Override @@ -54,6 +52,7 @@ public class TransportMainAction extends HandledTransportAction resourcesToClose = new ArrayList<>(); final ThreadPool threadPool = new ThreadPool(settings); + resourcesToClose.add(() -> ThreadPool.terminate(threadPool, 10, TimeUnit.SECONDS)); final NetworkService networkService = new NetworkService(settings); NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry(); - boolean success = false; try { ModulesBuilder modules = new ModulesBuilder(); - modules.add(new Version.Module(version)); // plugin modules must be added here, before others or we can get crazy injection errors... for (Module pluginModule : pluginsService.nodeModules()) { modules.add(pluginModule); } - modules.add(new PluginsModule(pluginsService)); modules.add(new NetworkModule(networkService, settings, true, namedWriteableRegistry)); modules.add(b -> b.bind(ThreadPool.class).toInstance(threadPool)); modules.add(new SearchModule(settings, namedWriteableRegistry) { @@ -156,21 +151,25 @@ public class TransportClient extends AbstractClient { SettingsModule settingsModule = new SettingsModule(settings, additionalSettings, additionalSettingsFilter); CircuitBreakerService circuitBreakerService = Node.createCircuitBreakerService(settingsModule.getSettings(), settingsModule.getClusterSettings()); + resourcesToClose.add(circuitBreakerService); + BigArrays bigArrays = new BigArrays(settings, circuitBreakerService); + resourcesToClose.add(bigArrays); modules.add(settingsModule); - modules.add((b -> b.bind(CircuitBreakerService.class).toInstance(circuitBreakerService))); + modules.add((b -> { + b.bind(BigArrays.class).toInstance(bigArrays); + b.bind(PluginsService.class).toInstance(pluginsService); + b.bind(CircuitBreakerService.class).toInstance(circuitBreakerService); + })); Injector injector = modules.createInjector(); final TransportService transportService = injector.getInstance(TransportService.class); transportService.start(); transportService.acceptIncomingRequests(); - TransportClient transportClient = new TransportClient(injector); - success = true; + resourcesToClose.clear(); return transportClient; } finally { - if (!success) { - ThreadPool.terminate(threadPool, 10, TimeUnit.SECONDS); - } + IOUtils.closeWhileHandlingException(resourcesToClose); } } } @@ -265,24 +264,16 @@ public class TransportClient extends AbstractClient { */ @Override public void close() { - injector.getInstance(TransportClientNodesService.class).close(); - injector.getInstance(TransportService.class).close(); - try { - injector.getInstance(MonitorService.class).close(); - } catch (Exception e) { - // ignore, might not be bounded - } + List closeables = new ArrayList<>(); + closeables.add(injector.getInstance(TransportClientNodesService.class)); + closeables.add(injector.getInstance(TransportService.class)); for (Class plugin : injector.getInstance(PluginsService.class).nodeServices()) { - injector.getInstance(plugin).close(); + closeables.add(injector.getInstance(plugin)); } - try { - ThreadPool.terminate(injector.getInstance(ThreadPool.class), 10, TimeUnit.SECONDS); - } catch (Exception e) { - // ignore - } - - injector.getInstance(BigArrays.class).close(); + closeables.add(() -> ThreadPool.terminate(injector.getInstance(ThreadPool.class), 10, TimeUnit.SECONDS)); + closeables.add(injector.getInstance(BigArrays.class)); + IOUtils.closeWhileHandlingException(closeables); } @Override diff --git a/core/src/main/java/org/elasticsearch/client/transport/TransportClientNodesService.java b/core/src/main/java/org/elasticsearch/client/transport/TransportClientNodesService.java index cfa8adc28a7..120a4711217 100644 --- a/core/src/main/java/org/elasticsearch/client/transport/TransportClientNodesService.java +++ b/core/src/main/java/org/elasticsearch/client/transport/TransportClientNodesService.java @@ -48,6 +48,7 @@ import org.elasticsearch.transport.TransportException; import org.elasticsearch.transport.TransportRequestOptions; import org.elasticsearch.transport.TransportService; +import java.io.Closeable; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -66,7 +67,7 @@ import static org.elasticsearch.common.unit.TimeValue.timeValueSeconds; /** * */ -public class TransportClientNodesService extends AbstractComponent { +public class TransportClientNodesService extends AbstractComponent implements Closeable { private final TimeValue nodesSamplerInterval; @@ -112,12 +113,12 @@ public class TransportClientNodesService extends AbstractComponent { @Inject public TransportClientNodesService(Settings settings,TransportService transportService, - ThreadPool threadPool, Version version) { + ThreadPool threadPool) { super(settings); this.clusterName = ClusterName.CLUSTER_NAME_SETTING.get(settings); this.transportService = transportService; this.threadPool = threadPool; - this.minCompatibilityVersion = version.minimumCompatibilityVersion(); + this.minCompatibilityVersion = Version.CURRENT.minimumCompatibilityVersion(); this.nodesSamplerInterval = CLIENT_TRANSPORT_NODES_SAMPLER_INTERVAL.get(this.settings); this.pingTimeout = CLIENT_TRANSPORT_PING_TIMEOUT.get(this.settings).millis(); diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java b/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java index 2b482635879..456675abcf1 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java @@ -103,7 +103,6 @@ public class MetaDataCreateIndexService extends AbstractComponent { private final ClusterService clusterService; private final IndicesService indicesService; private final AllocationService allocationService; - private final Version version; private final AliasValidator aliasValidator; private final IndexTemplateFilter indexTemplateFilter; private final Environment env; @@ -114,13 +113,12 @@ public class MetaDataCreateIndexService extends AbstractComponent { @Inject public MetaDataCreateIndexService(Settings settings, ClusterService clusterService, IndicesService indicesService, AllocationService allocationService, - Version version, AliasValidator aliasValidator, + AliasValidator aliasValidator, Set indexTemplateFilters, Environment env, NodeServicesProvider nodeServicesProvider, IndexScopedSettings indexScopedSettings) { super(settings); this.clusterService = clusterService; this.indicesService = indicesService; this.allocationService = allocationService; - this.version = version; this.aliasValidator = aliasValidator; this.env = env; this.nodeServicesProvider = nodeServicesProvider; @@ -287,7 +285,7 @@ public class MetaDataCreateIndexService extends AbstractComponent { if (indexSettingsBuilder.get(SETTING_VERSION_CREATED) == null) { DiscoveryNodes nodes = currentState.nodes(); - final Version createdVersion = Version.smallest(version, nodes.getSmallestNonClientNodeVersion()); + final Version createdVersion = Version.smallest(Version.CURRENT, nodes.getSmallestNonClientNodeVersion()); indexSettingsBuilder.put(SETTING_VERSION_CREATED, createdVersion); } diff --git a/core/src/main/java/org/elasticsearch/cluster/node/DiscoveryNodeService.java b/core/src/main/java/org/elasticsearch/cluster/node/DiscoveryNodeService.java index 177c67f2986..06d0c7dbf24 100644 --- a/core/src/main/java/org/elasticsearch/cluster/node/DiscoveryNodeService.java +++ b/core/src/main/java/org/elasticsearch/cluster/node/DiscoveryNodeService.java @@ -46,12 +46,10 @@ public class DiscoveryNodeService extends AbstractComponent { // don't use node.id.seed so it won't be seen as an attribute Setting.longSetting("node_id.seed", 0L, Long.MIN_VALUE, Property.NodeScope); private final List customAttributesProviders = new CopyOnWriteArrayList<>(); - private final Version version; @Inject - public DiscoveryNodeService(Settings settings, Version version) { + public DiscoveryNodeService(Settings settings) { super(settings); - this.version = version; } public static String generateNodeId(Settings settings) { @@ -93,7 +91,7 @@ public class DiscoveryNodeService extends AbstractComponent { } } return new DiscoveryNode(Node.NODE_NAME_SETTING.get(settings), nodeId, publishAddress, attributes, - roles, version); + roles, Version.CURRENT); } public interface CustomAttributesProvider { diff --git a/core/src/main/java/org/elasticsearch/cluster/service/ClusterService.java b/core/src/main/java/org/elasticsearch/cluster/service/ClusterService.java index 7573f260a54..50c91665485 100644 --- a/core/src/main/java/org/elasticsearch/cluster/service/ClusterService.java +++ b/core/src/main/java/org/elasticsearch/cluster/service/ClusterService.java @@ -237,7 +237,11 @@ public class ClusterService extends AbstractLifecycleComponent { * The local node. */ public DiscoveryNode localNode() { - return clusterState.getNodes().getLocalNode(); + DiscoveryNode localNode = clusterState.getNodes().getLocalNode(); + if (localNode == null) { + throw new IllegalStateException("No local node found. Is the node started?"); + } + return localNode; } public OperationRouting operationRouting() { diff --git a/core/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java b/core/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java index 0170c4218a2..817e109bf4d 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java +++ b/core/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java @@ -263,6 +263,9 @@ public abstract class AbstractScopedSettings extends AbstractComponent { List keys = scoredKeys.stream().map((a) -> a.v2()).collect(Collectors.toList()); if (keys.isEmpty() == false) { msg += " did you mean " + (keys.size() == 1 ? "[" + keys.get(0) + "]": "any of " + keys.toString()) + "?"; + } else { + msg += " please check that any required plugins are installed, or check the breaking changes documentation for removed " + + "settings"; } throw new IllegalArgumentException(msg); } diff --git a/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java b/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java index fb60453d467..bbbbe57618b 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java +++ b/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java @@ -134,6 +134,7 @@ public final class IndexScopedSettings extends AbstractScopedSettings { MapperService.INDEX_MAPPING_DEPTH_LIMIT_SETTING, BitsetFilterCache.INDEX_LOAD_RANDOM_ACCESS_FILTERS_EAGERLY_SETTING, IndexModule.INDEX_STORE_TYPE_SETTING, + IndexModule.INDEX_STORE_PRE_LOAD_SETTING, IndexModule.INDEX_QUERY_CACHE_ENABLED_SETTING, IndexModule.INDEX_QUERY_CACHE_EVERYTHING_SETTING, PrimaryShardAllocator.INDEX_RECOVERY_INITIAL_SHARDS_SETTING, diff --git a/core/src/main/java/org/elasticsearch/common/util/BigArrays.java b/core/src/main/java/org/elasticsearch/common/util/BigArrays.java index 017881a9218..c2c8e242acc 100644 --- a/core/src/main/java/org/elasticsearch/common/util/BigArrays.java +++ b/core/src/main/java/org/elasticsearch/common/util/BigArrays.java @@ -373,12 +373,11 @@ public class BigArrays implements Releasable { final boolean checkBreaker; private final BigArrays circuitBreakingInstance; - @Inject public BigArrays(Settings settings, @Nullable final CircuitBreakerService breakerService) { // Checking the breaker is disabled if not specified this(new PageCacheRecycler(settings), breakerService, false); } - + // public for tests public BigArrays(PageCacheRecycler recycler, @Nullable final CircuitBreakerService breakerService, boolean checkBreaker) { this.checkBreaker = checkBreaker; this.recycler = recycler; diff --git a/core/src/main/java/org/elasticsearch/discovery/zen/elect/ElectMasterService.java b/core/src/main/java/org/elasticsearch/discovery/zen/elect/ElectMasterService.java index 5ff79f112d2..76b7de6da08 100644 --- a/core/src/main/java/org/elasticsearch/discovery/zen/elect/ElectMasterService.java +++ b/core/src/main/java/org/elasticsearch/discovery/zen/elect/ElectMasterService.java @@ -53,9 +53,9 @@ public class ElectMasterService extends AbstractComponent { private volatile int minimumMasterNodes; @Inject - public ElectMasterService(Settings settings, Version version) { + public ElectMasterService(Settings settings) { super(settings); - this.minMasterVersion = version.minimumCompatibilityVersion(); + this.minMasterVersion = Version.CURRENT.minimumCompatibilityVersion(); this.minimumMasterNodes = DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.get(settings); logger.debug("using minimum_master_nodes [{}]", minimumMasterNodes); } diff --git a/core/src/main/java/org/elasticsearch/discovery/zen/ping/unicast/UnicastZenPing.java b/core/src/main/java/org/elasticsearch/discovery/zen/ping/unicast/UnicastZenPing.java index 0d3c7f9d086..06fc9eae13d 100644 --- a/core/src/main/java/org/elasticsearch/discovery/zen/ping/unicast/UnicastZenPing.java +++ b/core/src/main/java/org/elasticsearch/discovery/zen/ping/unicast/UnicastZenPing.java @@ -132,8 +132,7 @@ public class UnicastZenPing extends AbstractLifecycleComponent implemen @Inject public UnicastZenPing(Settings settings, ThreadPool threadPool, TransportService transportService, - Version version, ElectMasterService electMasterService, - @Nullable Set unicastHostsProviders) { + ElectMasterService electMasterService, @Nullable Set unicastHostsProviders) { super(settings); this.threadPool = threadPool; this.transportService = transportService; @@ -166,7 +165,7 @@ public class UnicastZenPing extends AbstractLifecycleComponent implemen TransportAddress[] addresses = transportService.addressesFromString(host, limitPortCounts); for (TransportAddress address : addresses) { configuredTargetNodes.add(new DiscoveryNode(UNICAST_NODE_PREFIX + unicastNodeIdGenerator.incrementAndGet() + "#", - address, emptyMap(), emptySet(), version.minimumCompatibilityVersion())); + address, emptyMap(), emptySet(), getVersion().minimumCompatibilityVersion())); } } catch (Exception e) { throw new IllegalArgumentException("Failed to resolve address for [" + host + "]", e); @@ -586,4 +585,8 @@ public class UnicastZenPing extends AbstractLifecycleComponent implemen } } } + + protected Version getVersion() { + return Version.CURRENT; // for tests + } } diff --git a/core/src/main/java/org/elasticsearch/env/EnvironmentModule.java b/core/src/main/java/org/elasticsearch/env/EnvironmentModule.java deleted file mode 100644 index 6a893a73437..00000000000 --- a/core/src/main/java/org/elasticsearch/env/EnvironmentModule.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.env; - -import org.elasticsearch.common.inject.AbstractModule; -import org.elasticsearch.threadpool.ThreadPool; - -/** - * - */ -public class EnvironmentModule extends AbstractModule { - - private final Environment environment; - private final ThreadPool threadPool; - - public EnvironmentModule(Environment environment, ThreadPool threadPool) { - this.threadPool = threadPool; - this.environment = environment; - } - - @Override - protected void configure() { - bind(ThreadPool.class).toInstance(threadPool); - bind(Environment.class).toInstance(environment); - } -} diff --git a/core/src/main/java/org/elasticsearch/env/NodeEnvironment.java b/core/src/main/java/org/elasticsearch/env/NodeEnvironment.java index 2b2aab2ccd2..8815d18769d 100644 --- a/core/src/main/java/org/elasticsearch/env/NodeEnvironment.java +++ b/core/src/main/java/org/elasticsearch/env/NodeEnvironment.java @@ -32,12 +32,9 @@ import org.elasticsearch.ElasticsearchException; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.common.SuppressForbidden; -import org.elasticsearch.common.UUIDs; import org.elasticsearch.common.component.AbstractComponent; -import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.io.FileSystemUtils; import org.elasticsearch.common.logging.DeprecationLogger; -import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; @@ -66,7 +63,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -167,7 +163,6 @@ public final class NodeEnvironment extends AbstractComponent implements Closeabl public static final String NODE_LOCK_FILENAME = "node.lock"; public static final String UPGRADE_LOCK_FILENAME = "upgrade.lock"; - @Inject public NodeEnvironment(Settings settings, Environment environment) throws IOException { super(settings); diff --git a/core/src/main/java/org/elasticsearch/env/NodeEnvironmentModule.java b/core/src/main/java/org/elasticsearch/env/NodeEnvironmentModule.java deleted file mode 100644 index 162c3108120..00000000000 --- a/core/src/main/java/org/elasticsearch/env/NodeEnvironmentModule.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.env; - -import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.inject.AbstractModule; - -/** - * - */ -public class NodeEnvironmentModule extends AbstractModule { - - private final NodeEnvironment nodeEnvironment; - - public NodeEnvironmentModule() { - this(null); - } - - public NodeEnvironmentModule(@Nullable NodeEnvironment nodeEnvironment) { - this.nodeEnvironment = nodeEnvironment; - } - - @Override - protected void configure() { - if (nodeEnvironment != null) { - bind(NodeEnvironment.class).toInstance(nodeEnvironment); - } else { - bind(NodeEnvironment.class).asEagerSingleton(); - } - } -} \ No newline at end of file diff --git a/core/src/main/java/org/elasticsearch/gateway/GatewayModule.java b/core/src/main/java/org/elasticsearch/gateway/GatewayModule.java index 651123882a5..f736c070272 100644 --- a/core/src/main/java/org/elasticsearch/gateway/GatewayModule.java +++ b/core/src/main/java/org/elasticsearch/gateway/GatewayModule.java @@ -27,11 +27,6 @@ import org.elasticsearch.common.settings.Settings; */ public class GatewayModule extends AbstractModule { - private final Settings settings; - - public GatewayModule(Settings settings) { - this.settings = settings; - } @Override protected void configure() { diff --git a/core/src/main/java/org/elasticsearch/index/IndexModule.java b/core/src/main/java/org/elasticsearch/index/IndexModule.java index 6ceabd1146d..d233faf4f19 100644 --- a/core/src/main/java/org/elasticsearch/index/IndexModule.java +++ b/core/src/main/java/org/elasticsearch/index/IndexModule.java @@ -45,6 +45,7 @@ import org.elasticsearch.indices.mapper.MapperRegistry; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -74,6 +75,14 @@ public final class IndexModule { public static final Setting INDEX_STORE_TYPE_SETTING = new Setting<>("index.store.type", "", Function.identity(), Property.IndexScope, Property.NodeScope); + + /** On which extensions to load data into the file-system cache upon opening of files. + * This only works with the mmap directory, and even in that case is still + * best-effort only. */ + public static final Setting> INDEX_STORE_PRE_LOAD_SETTING = + Setting.listSetting("index.store.preload", Collections.emptyList(), Function.identity(), + Property.IndexScope, Property.NodeScope); + public static final String SIMILARITY_SETTINGS_PREFIX = "index.similarity"; // whether to use the query cache diff --git a/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java b/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java index 26701703ce1..f20f2f5d372 100644 --- a/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java +++ b/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java @@ -53,6 +53,7 @@ import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.common.util.Callback; +import org.elasticsearch.common.util.CancellableThreads; import org.elasticsearch.common.util.concurrent.AbstractRunnable; import org.elasticsearch.common.util.concurrent.SuspendableRefContainer; import org.elasticsearch.index.Index; @@ -131,8 +132,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.stream.Collectors; public class IndexShard extends AbstractIndexShardComponent implements IndicesClusterStateService.Shard { @@ -158,6 +159,7 @@ public class IndexShard extends AbstractIndexShardComponent implements IndicesCl private final TranslogConfig translogConfig; private final IndexEventListener indexEventListener; private final QueryCachingPolicy cachingPolicy; + private final CancellableThreads cancellableThreads; /** @@ -265,6 +267,7 @@ public class IndexShard extends AbstractIndexShardComponent implements IndicesCl primaryTerm = indexSettings.getIndexMetaData().primaryTerm(shardId.id()); refreshListeners = buildRefreshListeners(); persistMetadata(shardRouting, null); + cancellableThreads = new CancellableThreads(); } public Store store() { @@ -843,6 +846,7 @@ public class IndexShard extends AbstractIndexShardComponent implements IndicesCl } finally { // playing safe here and close the engine even if the above succeeds - close can be called multiple times IOUtils.close(engine); } + cancellableThreads.cancel(reason); } } } @@ -1281,7 +1285,11 @@ public class IndexShard extends AbstractIndexShardComponent implements IndicesCl private void checkIndex() throws IOException { if (store.tryIncRef()) { try { - doCheckIndex(); + cancellableThreads.executeIO(this::doCheckIndex); + } catch (ClosedByInterruptException ex) { + assert cancellableThreads.isCancelled(); + // that's fine we might run into this when we cancel the thread since Java NIO will close the channel on interrupt + // and on the next access we fail it. } finally { store.decRef(); } diff --git a/core/src/main/java/org/elasticsearch/index/snapshots/blobstore/BlobStoreIndexShardRepository.java b/core/src/main/java/org/elasticsearch/index/snapshots/blobstore/BlobStoreIndexShardRepository.java index 94337ecdbc5..96230459934 100644 --- a/core/src/main/java/org/elasticsearch/index/snapshots/blobstore/BlobStoreIndexShardRepository.java +++ b/core/src/main/java/org/elasticsearch/index/snapshots/blobstore/BlobStoreIndexShardRepository.java @@ -105,8 +105,6 @@ public class BlobStoreIndexShardRepository extends AbstractComponent implements private RateLimiter restoreRateLimiter; - private RateLimiterListener rateLimiterListener; - private RateLimitingInputStream.Listener snapshotThrottleListener; private RateLimitingInputStream.Listener restoreThrottleListener; @@ -163,7 +161,6 @@ public class BlobStoreIndexShardRepository extends AbstractComponent implements this.chunkSize = chunkSize; this.snapshotRateLimiter = snapshotRateLimiter; this.restoreRateLimiter = restoreRateLimiter; - this.rateLimiterListener = rateLimiterListener; this.snapshotThrottleListener = nanos -> rateLimiterListener.onSnapshotPause(nanos); this.restoreThrottleListener = nanos -> rateLimiterListener.onRestorePause(nanos); this.compress = compress; diff --git a/core/src/main/java/org/elasticsearch/index/store/FsDirectoryService.java b/core/src/main/java/org/elasticsearch/index/store/FsDirectoryService.java index 5ad5c232f2e..69eedd7ef19 100644 --- a/core/src/main/java/org/elasticsearch/index/store/FsDirectoryService.java +++ b/core/src/main/java/org/elasticsearch/index/store/FsDirectoryService.java @@ -31,13 +31,11 @@ import org.apache.lucene.store.SimpleFSDirectory; import org.apache.lucene.store.SimpleFSLockFactory; import org.apache.lucene.store.SleepingLockWrapper; import org.apache.lucene.store.StoreRateLimiting; -import org.apache.lucene.util.Constants; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.metrics.CounterMetric; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; -import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.shard.ShardPath; @@ -45,7 +43,7 @@ import org.elasticsearch.index.shard.ShardPath; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Collections; +import java.util.HashSet; import java.util.Set; /** @@ -87,8 +85,12 @@ public class FsDirectoryService extends DirectoryService implements StoreRateLim @Override public Directory newDirectory() throws IOException { final Path location = path.resolveIndex(); + final LockFactory lockFactory = indexSettings.getValue(INDEX_LOCK_FACTOR_SETTING); Files.createDirectories(location); - Directory wrapped = newFSDirectory(location, indexSettings.getValue(INDEX_LOCK_FACTOR_SETTING)); + Directory wrapped = newFSDirectory(location, lockFactory); + Set preLoadExtensions = new HashSet<>( + indexSettings.getValue(IndexModule.INDEX_STORE_PRE_LOAD_SETTING)); + wrapped = setPreload(wrapped, location, lockFactory, preLoadExtensions); if (IndexMetaData.isOnSharedFilesystem(indexSettings.getSettings())) { wrapped = new SleepingLockWrapper(wrapped, 5000); } @@ -100,25 +102,11 @@ public class FsDirectoryService extends DirectoryService implements StoreRateLim rateLimitingTimeInNanos.inc(nanos); } - /* - * We are mmapping norms, docvalues as well as term dictionaries, all other files are served through NIOFS - * this provides good random access performance while not creating unnecessary mmaps for files like stored - * fields etc. - */ - private static final Set PRIMARY_EXTENSIONS = Collections.unmodifiableSet(Sets.newHashSet("nvd", "dvd", "tim")); - - protected Directory newFSDirectory(Path location, LockFactory lockFactory) throws IOException { final String storeType = indexSettings.getSettings().get(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), IndexModule.Type.FS.getSettingsKey()); - if (IndexModule.Type.FS.match(storeType) || isDefault(storeType)) { - final FSDirectory open = FSDirectory.open(location, lockFactory); // use lucene defaults - if (open instanceof MMapDirectory - && isDefault(storeType) - && Constants.WINDOWS == false) { - return newDefaultDir(location, (MMapDirectory) open, lockFactory); - } - return open; + if (IndexModule.Type.FS.match(storeType) || IndexModule.Type.DEFAULT.match(storeType)) { + return FSDirectory.open(location, lockFactory); // use lucene defaults } else if (IndexModule.Type.SIMPLEFS.match(storeType)) { return new SimpleFSDirectory(location, lockFactory); } else if (IndexModule.Type.NIOFS.match(storeType)) { @@ -129,17 +117,25 @@ public class FsDirectoryService extends DirectoryService implements StoreRateLim throw new IllegalArgumentException("No directory found for type [" + storeType + "]"); } - private static boolean isDefault(String storeType) { - return IndexModule.Type.DEFAULT.match(storeType); - } - - private Directory newDefaultDir(Path location, final MMapDirectory mmapDir, LockFactory lockFactory) throws IOException { - return new FileSwitchDirectory(PRIMARY_EXTENSIONS, mmapDir, new NIOFSDirectory(location, lockFactory), true) { - @Override - public String[] listAll() throws IOException { - // Avoid doing listAll twice: - return mmapDir.listAll(); + private static Directory setPreload(Directory directory, Path location, LockFactory lockFactory, + Set preLoadExtensions) throws IOException { + if (preLoadExtensions.isEmpty() == false + && directory instanceof MMapDirectory + && ((MMapDirectory) directory).getPreload() == false) { + if (preLoadExtensions.contains("*")) { + ((MMapDirectory) directory).setPreload(true); + return directory; } - }; + MMapDirectory primary = new MMapDirectory(location, lockFactory); + primary.setPreload(true); + return new FileSwitchDirectory(preLoadExtensions, primary, directory, true) { + @Override + public String[] listAll() throws IOException { + // avoid listing twice + return primary.listAll(); + } + }; + } + return directory; } } diff --git a/core/src/main/java/org/elasticsearch/node/Node.java b/core/src/main/java/org/elasticsearch/node/Node.java index a2a09938ead..de77f02ef51 100644 --- a/core/src/main/java/org/elasticsearch/node/Node.java +++ b/core/src/main/java/org/elasticsearch/node/Node.java @@ -27,7 +27,7 @@ import org.elasticsearch.ElasticsearchTimeoutException; import org.elasticsearch.Version; import org.elasticsearch.action.ActionModule; import org.elasticsearch.client.Client; -import org.elasticsearch.client.node.NodeClientModule; +import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.cluster.ClusterModule; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterStateObserver; @@ -67,9 +67,7 @@ import org.elasticsearch.discovery.Discovery; import org.elasticsearch.discovery.DiscoveryModule; import org.elasticsearch.discovery.DiscoverySettings; import org.elasticsearch.env.Environment; -import org.elasticsearch.env.EnvironmentModule; import org.elasticsearch.env.NodeEnvironment; -import org.elasticsearch.env.NodeEnvironmentModule; import org.elasticsearch.gateway.GatewayAllocator; import org.elasticsearch.gateway.GatewayModule; import org.elasticsearch.gateway.GatewayService; @@ -89,7 +87,6 @@ import org.elasticsearch.monitor.jvm.JvmInfo; import org.elasticsearch.node.internal.InternalSettingsPreparer; import org.elasticsearch.node.service.NodeService; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.plugins.PluginsModule; import org.elasticsearch.plugins.PluginsService; import org.elasticsearch.plugins.ScriptPlugin; import org.elasticsearch.repositories.RepositoriesModule; @@ -104,9 +101,7 @@ import org.elasticsearch.tasks.TaskPersistenceService; import org.elasticsearch.threadpool.ExecutorBuilder; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; -import org.elasticsearch.tribe.TribeModule; import org.elasticsearch.tribe.TribeService; -import org.elasticsearch.watcher.ResourceWatcherModule; import org.elasticsearch.watcher.ResourceWatcherService; import java.io.BufferedWriter; @@ -174,17 +169,17 @@ public class Node implements Closeable { * @param preparedSettings Base settings to configure the node with */ public Node(Settings preparedSettings) { - this(InternalSettingsPreparer.prepareEnvironment(preparedSettings, null), Version.CURRENT, Collections.>emptyList()); + this(InternalSettingsPreparer.prepareEnvironment(preparedSettings, null), Collections.>emptyList()); } - protected Node(Environment tmpEnv, Version version, Collection> classpathPlugins) { + protected Node(Environment tmpEnv, Collection> classpathPlugins) { Settings tmpSettings = Settings.builder().put(tmpEnv.settings()) .put(Client.CLIENT_TYPE_SETTING_S.getKey(), CLIENT_TYPE).build(); final List resourcesToClose = new ArrayList<>(); // register everything we need to release in the case of an error tmpSettings = TribeService.processSettings(tmpSettings); ESLogger logger = Loggers.getLogger(Node.class, NODE_NAME_SETTING.get(tmpSettings)); - final String displayVersion = version + (Build.CURRENT.isSnapshot() ? "-SNAPSHOT" : ""); + final String displayVersion = Version.CURRENT + (Build.CURRENT.isSnapshot() ? "-SNAPSHOT" : ""); final JvmInfo jvmInfo = JvmInfo.jvmInfo(); logger.info( "version[{}], pid[{}], build[{}/{}], OS[{}/{}/{}], JVM[{}/{}/{}/{}]", @@ -242,40 +237,50 @@ public class Node implements Closeable { } catch (IOException ex) { throw new IllegalStateException("Failed to created node environment", ex); } + final ResourceWatcherService resourceWatcherService = new ResourceWatcherService(settings, threadPool); + resourcesToClose.add(resourceWatcherService); final NetworkService networkService = new NetworkService(settings); final ClusterService clusterService = new ClusterService(settings, settingsModule.getClusterSettings(), threadPool); resourcesToClose.add(clusterService); + final TribeService tribeService = new TribeService(settings, clusterService); + resourcesToClose.add(tribeService); NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry(); ModulesBuilder modules = new ModulesBuilder(); - modules.add(new Version.Module(version)); // plugin modules must be added here, before others or we can get crazy injection errors... for (Module pluginModule : pluginsService.nodeModules()) { modules.add(pluginModule); } final MonitorService monitorService = new MonitorService(settings, nodeEnvironment, threadPool); - modules.add(new PluginsModule(pluginsService)); - modules.add(new EnvironmentModule(environment, threadPool)); modules.add(new NodeModule(this, monitorService)); modules.add(new NetworkModule(networkService, settings, false, namedWriteableRegistry)); modules.add(scriptModule); - modules.add(new NodeEnvironmentModule(nodeEnvironment)); modules.add(new DiscoveryModule(this.settings)); modules.add(new ClusterModule(this.settings, clusterService)); modules.add(new IndicesModule(namedWriteableRegistry)); modules.add(new SearchModule(settings, namedWriteableRegistry)); modules.add(new ActionModule(DiscoveryNode.isIngestNode(settings), false)); - modules.add(new GatewayModule(settings)); - modules.add(new NodeClientModule()); - modules.add(new ResourceWatcherModule()); + modules.add(new GatewayModule()); modules.add(new RepositoriesModule()); - modules.add(new TribeModule()); modules.add(new AnalysisModule(environment)); pluginsService.processModules(modules); CircuitBreakerService circuitBreakerService = createCircuitBreakerService(settingsModule.getSettings(), settingsModule.getClusterSettings()); resourcesToClose.add(circuitBreakerService); + BigArrays bigArrays = createBigArrays(settings, circuitBreakerService); + resourcesToClose.add(bigArrays); modules.add(settingsModule); - modules.add(b -> b.bind(CircuitBreakerService.class).toInstance(circuitBreakerService)); + modules.add(b -> { + b.bind(PluginsService.class).toInstance(pluginsService); + b.bind(Client.class).to(NodeClient.class).asEagerSingleton(); + b.bind(Environment.class).toInstance(environment); + b.bind(ThreadPool.class).toInstance(threadPool); + b.bind(NodeEnvironment.class).toInstance(nodeEnvironment); + b.bind(TribeService.class).toInstance(tribeService); + b.bind(ResourceWatcherService.class).toInstance(resourceWatcherService); + b.bind(CircuitBreakerService.class).toInstance(circuitBreakerService); + b.bind(BigArrays.class).toInstance(bigArrays); + } + ); injector = modules.createInjector(); client = injector.getInstance(Client.class); success = true; @@ -624,4 +629,12 @@ public class Node implements Closeable { throw new IllegalArgumentException("Unknown circuit breaker type [" + type + "]"); } } + + /** + * Creates a new {@link BigArrays} instance used for this node. + * This method can be overwritten by subclasses to change their {@link BigArrays} implementation for instance for testing + */ + BigArrays createBigArrays(Settings settings, CircuitBreakerService circuitBreakerService) { + return new BigArrays(settings, circuitBreakerService); + } } diff --git a/core/src/main/java/org/elasticsearch/node/NodeModule.java b/core/src/main/java/org/elasticsearch/node/NodeModule.java index c5d087c0ef2..85cfe5bd6b2 100644 --- a/core/src/main/java/org/elasticsearch/node/NodeModule.java +++ b/core/src/main/java/org/elasticsearch/node/NodeModule.java @@ -37,9 +37,6 @@ public class NodeModule extends AbstractModule { private final MonitorService monitorService; private final ProcessorsRegistry.Builder processorsRegistryBuilder; - // pkg private so tests can mock - Class bigArraysImpl = BigArrays.class; - public NodeModule(Node node, MonitorService monitorService) { this.node = node; this.monitorService = monitorService; @@ -48,12 +45,6 @@ public class NodeModule extends AbstractModule { @Override protected void configure() { - if (bigArraysImpl == BigArrays.class) { - bind(BigArrays.class).asEagerSingleton(); - } else { - bind(BigArrays.class).to(bigArraysImpl).asEagerSingleton(); - } - bind(Node.class).toInstance(node); bind(MonitorService.class).toInstance(monitorService); bind(NodeService.class).asEagerSingleton(); diff --git a/core/src/main/java/org/elasticsearch/node/service/NodeService.java b/core/src/main/java/org/elasticsearch/node/service/NodeService.java index 1cbdfe12d2c..6a07565b6cd 100644 --- a/core/src/main/java/org/elasticsearch/node/service/NodeService.java +++ b/core/src/main/java/org/elasticsearch/node/service/NodeService.java @@ -70,14 +70,12 @@ public class NodeService extends AbstractComponent implements Closeable { private volatile Map serviceAttributes = emptyMap(); - private final Version version; - private final Discovery discovery; @Inject public NodeService(Settings settings, ThreadPool threadPool, MonitorService monitorService, Discovery discovery, TransportService transportService, IndicesService indicesService, - PluginsService pluginService, CircuitBreakerService circuitBreakerService, Version version, + PluginsService pluginService, CircuitBreakerService circuitBreakerService, ProcessorsRegistry.Builder processorsRegistryBuilder, ClusterService clusterService, SettingsFilter settingsFilter) { super(settings); this.threadPool = threadPool; @@ -85,7 +83,6 @@ public class NodeService extends AbstractComponent implements Closeable { this.transportService = transportService; this.indicesService = indicesService; this.discovery = discovery; - this.version = version; this.pluginService = pluginService; this.circuitBreakerService = circuitBreakerService; this.clusterService = clusterService; @@ -126,7 +123,7 @@ public class NodeService extends AbstractComponent implements Closeable { } public NodeInfo info() { - return new NodeInfo(version, Build.CURRENT, discovery.localNode(), serviceAttributes, + return new NodeInfo(Version.CURRENT, Build.CURRENT, discovery.localNode(), serviceAttributes, settings, monitorService.osService().info(), monitorService.processService().info(), @@ -141,7 +138,7 @@ public class NodeService extends AbstractComponent implements Closeable { public NodeInfo info(boolean settings, boolean os, boolean process, boolean jvm, boolean threadPool, boolean transport, boolean http, boolean plugin, boolean ingest) { - return new NodeInfo(version, Build.CURRENT, discovery.localNode(), serviceAttributes, + return new NodeInfo(Version.CURRENT, Build.CURRENT, discovery.localNode(), serviceAttributes, settings ? settingsFilter.filter(this.settings) : null, os ? monitorService.osService().info() : null, process ? monitorService.processService().info() : null, diff --git a/core/src/main/java/org/elasticsearch/plugins/PluginsModule.java b/core/src/main/java/org/elasticsearch/plugins/PluginsModule.java deleted file mode 100644 index 04e468cdd6c..00000000000 --- a/core/src/main/java/org/elasticsearch/plugins/PluginsModule.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.plugins; - -import org.elasticsearch.common.inject.AbstractModule; - -public class PluginsModule extends AbstractModule { - - private final PluginsService pluginsService; - - public PluginsModule(PluginsService pluginsService) { - this.pluginsService = pluginsService; - } - - @Override - protected void configure() { - bind(PluginsService.class).toInstance(pluginsService); - } -} diff --git a/core/src/main/java/org/elasticsearch/script/CompiledScript.java b/core/src/main/java/org/elasticsearch/script/CompiledScript.java index aa34678c041..ec2ad4192a2 100644 --- a/core/src/main/java/org/elasticsearch/script/CompiledScript.java +++ b/core/src/main/java/org/elasticsearch/script/CompiledScript.java @@ -39,9 +39,9 @@ public class CompiledScript { public CompiledScript(ScriptService.ScriptType type, String name, String lang, Object compiled) { this.type = type; this.name = name; - this.lang = lang; - this.compiled = compiled; - } + this.lang = lang; + this.compiled = compiled; + } /** * Method to get the type of language. diff --git a/core/src/main/java/org/elasticsearch/script/NativeScriptEngineService.java b/core/src/main/java/org/elasticsearch/script/NativeScriptEngineService.java index c9bfdfc1670..191c2b4bcf7 100644 --- a/core/src/main/java/org/elasticsearch/script/NativeScriptEngineService.java +++ b/core/src/main/java/org/elasticsearch/script/NativeScriptEngineService.java @@ -90,11 +90,6 @@ public class NativeScriptEngineService extends AbstractComponent implements Scri public void close() { } - @Override - public void scriptRemoved(CompiledScript script) { - // Nothing to do here - } - @Override public boolean isInlineScriptEnabled() { return true; diff --git a/core/src/main/java/org/elasticsearch/script/ScriptEngineService.java b/core/src/main/java/org/elasticsearch/script/ScriptEngineService.java index ab49c3c8011..55a931d8d57 100644 --- a/core/src/main/java/org/elasticsearch/script/ScriptEngineService.java +++ b/core/src/main/java/org/elasticsearch/script/ScriptEngineService.java @@ -23,7 +23,6 @@ import org.elasticsearch.common.Nullable; import org.elasticsearch.search.lookup.SearchLookup; import java.io.Closeable; -import java.util.List; import java.util.Map; /** @@ -49,13 +48,6 @@ public interface ScriptEngineService extends Closeable { SearchScript search(CompiledScript compiledScript, SearchLookup lookup, @Nullable Map vars); - /** - * Handler method called when a script is removed from the Guava cache. - * - * The passed script may be null if it has already been garbage collected. - * */ - void scriptRemoved(@Nullable CompiledScript script); - /** * Returns true if this scripting engine can safely accept inline scripts by default. The default is false */ diff --git a/core/src/main/java/org/elasticsearch/script/ScriptService.java b/core/src/main/java/org/elasticsearch/script/ScriptService.java index fe3eaa29142..8f939f265a4 100644 --- a/core/src/main/java/org/elasticsearch/script/ScriptService.java +++ b/core/src/main/java/org/elasticsearch/script/ScriptService.java @@ -507,16 +507,10 @@ public class ScriptService extends AbstractComponent implements Closeable { private class ScriptCacheRemovalListener implements RemovalListener { @Override public void onRemoval(RemovalNotification notification) { - scriptMetrics.onCacheEviction(); - for (ScriptEngineService service : scriptEngines) { - try { - service.scriptRemoved(notification.getValue()); - } catch (Exception e) { - logger.warn("exception calling script removal listener for script service", e); - // We don't rethrow because Guava would just catch the - // exception and log it, which we have already done - } + if (logger.isDebugEnabled()) { + logger.debug("removed {} from cache, reason: {}", notification.getValue(), notification.getRemovalReason()); } + scriptMetrics.onCacheEviction(); } } diff --git a/core/src/main/java/org/elasticsearch/transport/local/LocalTransport.java b/core/src/main/java/org/elasticsearch/transport/local/LocalTransport.java index d1ac749e4ac..4caf1a543c0 100644 --- a/core/src/main/java/org/elasticsearch/transport/local/LocalTransport.java +++ b/core/src/main/java/org/elasticsearch/transport/local/LocalTransport.java @@ -77,7 +77,6 @@ public class LocalTransport extends AbstractLifecycleComponent implem public static final String LOCAL_TRANSPORT_THREAD_NAME_PREFIX = "local_transport"; final ThreadPool threadPool; private final ThreadPoolExecutor workers; - private final Version version; private volatile TransportServiceAdapter transportServiceAdapter; private volatile BoundTransportAddress boundAddress; private volatile LocalTransportAddress localAddress; @@ -92,11 +91,10 @@ public class LocalTransport extends AbstractLifecycleComponent implem public static final String TRANSPORT_LOCAL_QUEUE = "transport.local.queue"; @Inject - public LocalTransport(Settings settings, ThreadPool threadPool, Version version, + public LocalTransport(Settings settings, ThreadPool threadPool, NamedWriteableRegistry namedWriteableRegistry, CircuitBreakerService circuitBreakerService) { super(settings); this.threadPool = threadPool; - this.version = version; int workerCount = this.settings.getAsInt(TRANSPORT_LOCAL_WORKERS, EsExecutors.boundedNumberOfProcessors(settings)); int queueSize = this.settings.getAsInt(TRANSPORT_LOCAL_QUEUE, -1); logger.debug("creating [{}] workers, queue_size [{}]", workerCount, queueSize); @@ -207,7 +205,7 @@ public class LocalTransport extends AbstractLifecycleComponent implem @Override public void sendRequest(final DiscoveryNode node, final long requestId, final String action, final TransportRequest request, TransportRequestOptions options) throws IOException, TransportException { - final Version version = Version.smallest(node.getVersion(), this.version); + final Version version = Version.smallest(node.getVersion(), getVersion()); try (BytesStreamOutput stream = new BytesStreamOutput()) { stream.setVersion(version); @@ -404,4 +402,8 @@ public class LocalTransport extends AbstractLifecycleComponent implem public List getLocalAddresses() { return Collections.singletonList("0.0.0.0"); } + + protected Version getVersion() { // for tests + return Version.CURRENT; + } } diff --git a/core/src/main/java/org/elasticsearch/transport/netty/NettyTransport.java b/core/src/main/java/org/elasticsearch/transport/netty/NettyTransport.java index a5542f9b403..c9f02066836 100644 --- a/core/src/main/java/org/elasticsearch/transport/netty/NettyTransport.java +++ b/core/src/main/java/org/elasticsearch/transport/netty/NettyTransport.java @@ -210,7 +210,6 @@ public class NettyTransport extends AbstractLifecycleComponent implem intSetting("transport.netty.boss_count", 1, 1, Property.NodeScope); protected final NetworkService networkService; - protected final Version version; protected final boolean blockingClient; protected final TimeValue connectTimeout; @@ -254,13 +253,12 @@ public class NettyTransport extends AbstractLifecycleComponent implem final ScheduledPing scheduledPing; @Inject - public NettyTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, Version version, + public NettyTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, NamedWriteableRegistry namedWriteableRegistry, CircuitBreakerService circuitBreakerService) { super(settings); this.threadPool = threadPool; this.networkService = networkService; this.bigArrays = bigArrays; - this.version = version; this.workerCount = WORKER_COUNT.get(settings); this.blockingClient = TCP_BLOCKING_CLIENT.get(settings); @@ -894,7 +892,7 @@ public class NettyTransport extends AbstractLifecycleComponent implem // we pick the smallest of the 2, to support both backward and forward compatibility // note, this is the only place we need to do this, since from here on, we use the serialized version // as the version to use also when the node receiving this request will send the response with - Version version = Version.smallest(this.version, node.getVersion()); + Version version = Version.smallest(getCurrentVersion(), node.getVersion()); stream.setVersion(version); threadPool.getThreadContext().writeTo(stream); @@ -1401,4 +1399,9 @@ public class NettyTransport extends AbstractLifecycleComponent implem } } } + + protected Version getCurrentVersion() { + // this is just for tests to mock stuff like the nodes version - tests can override this internally + return Version.CURRENT; + } } diff --git a/core/src/main/java/org/elasticsearch/tribe/TribeClientNode.java b/core/src/main/java/org/elasticsearch/tribe/TribeClientNode.java index 688dfe5a92d..02957ab99a4 100644 --- a/core/src/main/java/org/elasticsearch/tribe/TribeClientNode.java +++ b/core/src/main/java/org/elasticsearch/tribe/TribeClientNode.java @@ -19,7 +19,6 @@ package org.elasticsearch.tribe; -import org.elasticsearch.Version; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.node.Node; @@ -32,6 +31,6 @@ import java.util.Collections; */ class TribeClientNode extends Node { TribeClientNode(Settings settings) { - super(new Environment(settings), Version.CURRENT, Collections.>emptyList()); + super(new Environment(settings), Collections.>emptyList()); } } diff --git a/core/src/main/java/org/elasticsearch/tribe/TribeModule.java b/core/src/main/java/org/elasticsearch/tribe/TribeModule.java deleted file mode 100644 index fb642d1b034..00000000000 --- a/core/src/main/java/org/elasticsearch/tribe/TribeModule.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.tribe; - -import org.elasticsearch.common.inject.AbstractModule; - -/** - */ -public class TribeModule extends AbstractModule { - - @Override - protected void configure() { - bind(TribeService.class).asEagerSingleton(); - } -} diff --git a/core/src/main/java/org/elasticsearch/tribe/TribeService.java b/core/src/main/java/org/elasticsearch/tribe/TribeService.java index 50be6e39b07..259a9d443a3 100644 --- a/core/src/main/java/org/elasticsearch/tribe/TribeService.java +++ b/core/src/main/java/org/elasticsearch/tribe/TribeService.java @@ -40,7 +40,6 @@ import org.elasticsearch.common.Priority; import org.elasticsearch.common.Strings; import org.elasticsearch.common.UUIDs; import org.elasticsearch.common.component.AbstractLifecycleComponent; -import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkService; import org.elasticsearch.common.regex.Regex; @@ -175,7 +174,6 @@ public class TribeService extends AbstractLifecycleComponent { private final List nodes = new CopyOnWriteArrayList<>(); - @Inject public TribeService(Settings settings, ClusterService clusterService) { super(settings); this.clusterService = clusterService; diff --git a/core/src/main/java/org/elasticsearch/watcher/ResourceWatcherModule.java b/core/src/main/java/org/elasticsearch/watcher/ResourceWatcherModule.java deleted file mode 100644 index a3ae84a954f..00000000000 --- a/core/src/main/java/org/elasticsearch/watcher/ResourceWatcherModule.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.elasticsearch.watcher; - -import org.elasticsearch.common.inject.AbstractModule; - -/** - * - */ -public class ResourceWatcherModule extends AbstractModule { - @Override - protected void configure() { - bind(ResourceWatcherService.class).asEagerSingleton(); - } -} diff --git a/core/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TaskManagerTestCase.java b/core/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TaskManagerTestCase.java index e317d4e6d7a..eec285e7ffb 100644 --- a/core/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TaskManagerTestCase.java +++ b/core/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TaskManagerTestCase.java @@ -167,7 +167,7 @@ public abstract class TaskManagerTestCase extends ESTestCase { public TestNode(String name, ThreadPool threadPool, Settings settings) { clusterService = createClusterService(threadPool); transportService = new TransportService(settings, - new LocalTransport(settings, threadPool, Version.CURRENT, new NamedWriteableRegistry(), + new LocalTransport(settings, threadPool, new NamedWriteableRegistry(), new NoneCircuitBreakerService()), threadPool) { @Override protected TaskManager createTaskManager() { diff --git a/core/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexIT.java b/core/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexIT.java index 8fbb489d9c2..3e7323dceeb 100644 --- a/core/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexIT.java +++ b/core/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexIT.java @@ -70,7 +70,8 @@ public class CreateIndexIT extends ESIntegTestCase { prepareCreate("test").setSettings(Settings.builder().put(IndexMetaData.SETTING_CREATION_DATE, 4L)).get(); fail(); } catch (IllegalArgumentException ex) { - assertEquals("unknown setting [index.creation_date]", ex.getMessage()); + assertEquals("unknown setting [index.creation_date] please check that any required plugins are installed, or check the " + + "breaking changes documentation for removed settings", ex.getMessage()); } } @@ -165,7 +166,8 @@ public class CreateIndexIT extends ESIntegTestCase { .get(); fail("should have thrown an exception about the shard count"); } catch (IllegalArgumentException e) { - assertEquals("unknown setting [index.unknown.value]", e.getMessage()); + assertEquals("unknown setting [index.unknown.value] please check that any required plugins are installed, or check the" + + " breaking changes documentation for removed settings", e.getMessage()); } } @@ -211,13 +213,16 @@ public class CreateIndexIT extends ESIntegTestCase { @Override public void run() { try { - client().prepareIndex("test", "test").setSource("index_version", indexVersion.get()).get(); // recreate that index + // recreate that index + client().prepareIndex("test", "test").setSource("index_version", indexVersion.get()).get(); synchronized (indexVersionLock) { - // we sync here since we have to ensure that all indexing operations below for a given ID are done before we increment the - // index version otherwise a doc that is in-flight could make it into an index that it was supposed to be deleted for and our assertion fail... + // we sync here since we have to ensure that all indexing operations below for a given ID are done before + // we increment the index version otherwise a doc that is in-flight could make it into an index that it + // was supposed to be deleted for and our assertion fail... indexVersion.incrementAndGet(); } - assertAcked(client().admin().indices().prepareDelete("test").get()); // from here on all docs with index_version == 0|1 must be gone!!!! only 2 are ok; + // from here on all docs with index_version == 0|1 must be gone!!!! only 2 are ok; + assertAcked(client().admin().indices().prepareDelete("test").get()); } finally { latch.countDown(); } @@ -249,8 +254,10 @@ public class CreateIndexIT extends ESIntegTestCase { latch.await(); refresh(); - // we only really assert that we never reuse segments of old indices or anything like this here and that nothing fails with crazy exceptions - SearchResponse expected = client().prepareSearch("test").setIndicesOptions(IndicesOptions.lenientExpandOpen()).setQuery(new RangeQueryBuilder("index_version").from(indexVersion.get(), true)).get(); + // we only really assert that we never reuse segments of old indices or anything like this here and that nothing fails with + // crazy exceptions + SearchResponse expected = client().prepareSearch("test").setIndicesOptions(IndicesOptions.lenientExpandOpen()) + .setQuery(new RangeQueryBuilder("index_version").from(indexVersion.get(), true)).get(); SearchResponse all = client().prepareSearch("test").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get(); assertEquals(expected + " vs. " + all, expected.getHits().getTotalHits(), all.getHits().getTotalHits()); logger.info("total: {}", expected.getHits().getTotalHits()); @@ -283,7 +290,8 @@ public class CreateIndexIT extends ESIntegTestCase { } public void testRestartIndexCreationAfterFullClusterRestart() throws Exception { - client().admin().cluster().prepareUpdateSettings().setTransientSettings(Settings.builder().put("cluster.routing.allocation.enable", "none")).get(); + client().admin().cluster().prepareUpdateSettings().setTransientSettings(Settings.builder().put("cluster.routing.allocation.enable", + "none")).get(); client().admin().indices().prepareCreate("test").setSettings(indexSettings()).get(); internalCluster().fullRestart(); ensureGreen("test"); diff --git a/core/src/test/java/org/elasticsearch/action/admin/indices/template/put/MetaDataIndexTemplateServiceTests.java b/core/src/test/java/org/elasticsearch/action/admin/indices/template/put/MetaDataIndexTemplateServiceTests.java index 4c3f21f988d..d62fe30f6fa 100644 --- a/core/src/test/java/org/elasticsearch/action/admin/indices/template/put/MetaDataIndexTemplateServiceTests.java +++ b/core/src/test/java/org/elasticsearch/action/admin/indices/template/put/MetaDataIndexTemplateServiceTests.java @@ -158,7 +158,6 @@ public class MetaDataIndexTemplateServiceTests extends ESSingleNodeTestCase { null, null, null, - Version.CURRENT, null, new HashSet<>(), null, @@ -189,7 +188,6 @@ public class MetaDataIndexTemplateServiceTests extends ESSingleNodeTestCase { clusterService, indicesService, null, - Version.CURRENT, null, new HashSet<>(), null, diff --git a/core/src/test/java/org/elasticsearch/action/main/MainActionTests.java b/core/src/test/java/org/elasticsearch/action/main/MainActionTests.java index ce3fa93d214..2bff71d3c40 100644 --- a/core/src/test/java/org/elasticsearch/action/main/MainActionTests.java +++ b/core/src/test/java/org/elasticsearch/action/main/MainActionTests.java @@ -112,7 +112,7 @@ public class MainActionTests extends ESTestCase { when(clusterService.state()).thenReturn(state); TransportMainAction action = new TransportMainAction(settings, mock(ThreadPool.class), mock(TransportService.class), - mock(ActionFilters.class), mock(IndexNameExpressionResolver.class), clusterService, Version.CURRENT); + mock(ActionFilters.class), mock(IndexNameExpressionResolver.class), clusterService); AtomicReference responseRef = new AtomicReference<>(); action.doExecute(new MainRequest(), new ActionListener() { @Override diff --git a/core/src/test/java/org/elasticsearch/action/support/replication/BroadcastReplicationTests.java b/core/src/test/java/org/elasticsearch/action/support/replication/BroadcastReplicationTests.java index abebb61c0b7..e7971dd4c1d 100644 --- a/core/src/test/java/org/elasticsearch/action/support/replication/BroadcastReplicationTests.java +++ b/core/src/test/java/org/elasticsearch/action/support/replication/BroadcastReplicationTests.java @@ -89,7 +89,7 @@ public class BroadcastReplicationTests extends ESTestCase { @Before public void setUp() throws Exception { super.setUp(); - LocalTransport transport = new LocalTransport(Settings.EMPTY, threadPool, Version.CURRENT, new NamedWriteableRegistry(), circuitBreakerService); + LocalTransport transport = new LocalTransport(Settings.EMPTY, threadPool, new NamedWriteableRegistry(), circuitBreakerService); clusterService = createClusterService(threadPool); transportService = new TransportService(clusterService.getSettings(), transport, threadPool); transportService.start(); diff --git a/core/src/test/java/org/elasticsearch/client/transport/TransportClientNodesServiceTests.java b/core/src/test/java/org/elasticsearch/client/transport/TransportClientNodesServiceTests.java index 2a32ebd05af..5c07f5e6f25 100644 --- a/core/src/test/java/org/elasticsearch/client/transport/TransportClientNodesServiceTests.java +++ b/core/src/test/java/org/elasticsearch/client/transport/TransportClientNodesServiceTests.java @@ -102,7 +102,7 @@ public class TransportClientNodesServiceTests extends ESTestCase { transportService.start(); transportService.acceptIncomingRequests(); transportClientNodesService = - new TransportClientNodesService(settings, transportService, threadPool, Version.CURRENT); + new TransportClientNodesService(settings, transportService, threadPool); this.nodesCount = randomIntBetween(1, 10); for (int i = 0; i < nodesCount; i++) { transportClientNodesService.addTransportAddresses(new LocalTransportAddress("node" + i)); diff --git a/core/src/test/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexServiceTests.java b/core/src/test/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexServiceTests.java index 28a25d17337..04d27020273 100644 --- a/core/src/test/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexServiceTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexServiceTests.java @@ -212,7 +212,6 @@ public class MetaDataCreateIndexServiceTests extends ESTestCase { null, null, null, - Version.CURRENT, null, new HashSet<>(), null, diff --git a/core/src/test/java/org/elasticsearch/cluster/node/DiscoveryNodeServiceTests.java b/core/src/test/java/org/elasticsearch/cluster/node/DiscoveryNodeServiceTests.java index c03a5ab06dc..fb38a428a76 100644 --- a/core/src/test/java/org/elasticsearch/cluster/node/DiscoveryNodeServiceTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/node/DiscoveryNodeServiceTests.java @@ -54,7 +54,7 @@ public class DiscoveryNodeServiceTests extends ESTestCase { } } } - DiscoveryNodeService discoveryNodeService = new DiscoveryNodeService(builder.build(), Version.CURRENT); + DiscoveryNodeService discoveryNodeService = new DiscoveryNodeService(builder.build()); DiscoveryNode discoveryNode = discoveryNodeService.buildLocalNode(DummyTransportAddress.INSTANCE); assertThat(discoveryNode.getRoles(), equalTo(selectedRoles)); assertThat(discoveryNode.getAttributes(), equalTo(expectedAttributes)); @@ -68,7 +68,7 @@ public class DiscoveryNodeServiceTests extends ESTestCase { builder.put("node.attr.attr" + i, "value" + i); expectedAttributes.put("attr" + i, "value" + i); } - DiscoveryNodeService discoveryNodeService = new DiscoveryNodeService(builder.build(), Version.CURRENT); + DiscoveryNodeService discoveryNodeService = new DiscoveryNodeService(builder.build()); int numCustomAttributes = randomIntBetween(0, 5); Map customAttributes = new HashMap<>(); for (int i = 0; i < numCustomAttributes; i++) { diff --git a/core/src/test/java/org/elasticsearch/common/network/NetworkModuleTests.java b/core/src/test/java/org/elasticsearch/common/network/NetworkModuleTests.java index d5fc4630bcf..9868d92129f 100644 --- a/core/src/test/java/org/elasticsearch/common/network/NetworkModuleTests.java +++ b/core/src/test/java/org/elasticsearch/common/network/NetworkModuleTests.java @@ -58,7 +58,7 @@ public class NetworkModuleTests extends ModuleTestCase { static class FakeTransport extends AssertingLocalTransport { public FakeTransport() { - super(null, null, null, null, null); + super(null, null, null, null); } } diff --git a/core/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java b/core/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java index 3afd60d86e4..664f8cb96ab 100644 --- a/core/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java +++ b/core/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java @@ -202,20 +202,22 @@ public class ScopedSettingsTests extends ESTestCase { IndexScopedSettings settings = new IndexScopedSettings( Settings.EMPTY, IndexScopedSettings.BUILT_IN_INDEX_SETTINGS); + String unknownMsgSuffix = " please check that any required plugins are installed, or check the breaking changes documentation for" + + " removed settings"; settings.validate(Settings.builder().put("index.store.type", "boom")); settings.validate(Settings.builder().put("index.store.type", "boom").build()); try { settings.validate(Settings.builder().put("index.store.type", "boom", "i.am.not.a.setting", true)); fail(); } catch (IllegalArgumentException e) { - assertEquals("unknown setting [i.am.not.a.setting]", e.getMessage()); + assertEquals("unknown setting [i.am.not.a.setting]" + unknownMsgSuffix, e.getMessage()); } try { settings.validate(Settings.builder().put("index.store.type", "boom", "i.am.not.a.setting", true).build()); fail(); } catch (IllegalArgumentException e) { - assertEquals("unknown setting [i.am.not.a.setting]", e.getMessage()); + assertEquals("unknown setting [i.am.not.a.setting]" + unknownMsgSuffix, e.getMessage()); } try { diff --git a/core/src/test/java/org/elasticsearch/common/settings/SettingsModuleTests.java b/core/src/test/java/org/elasticsearch/common/settings/SettingsModuleTests.java index 353b7b61d6c..692134916ef 100644 --- a/core/src/test/java/org/elasticsearch/common/settings/SettingsModuleTests.java +++ b/core/src/test/java/org/elasticsearch/common/settings/SettingsModuleTests.java @@ -51,7 +51,8 @@ public class SettingsModuleTests extends ModuleTestCase { () -> new SettingsModule(settings)); assertEquals("Failed to parse value [[2.0]] for setting [cluster.routing.allocation.balance.shard]", ex.getMessage()); assertEquals(1, ex.getSuppressed().length); - assertEquals("unknown setting [some.foo.bar]", ex.getSuppressed()[0].getMessage()); + assertEquals("unknown setting [some.foo.bar] please check that any required plugins are installed, or check the breaking " + + "changes documentation for removed settings", ex.getSuppressed()[0].getMessage()); } { @@ -127,7 +128,8 @@ public class SettingsModuleTests extends ModuleTestCase { new SettingsModule(settings); fail(); } catch (IllegalArgumentException ex) { - assertEquals("tribe.blocks validation failed: unknown setting [wtf]", ex.getMessage()); + assertEquals("tribe.blocks validation failed: unknown setting [wtf] please check that any required plugins are" + + " installed, or check the breaking changes documentation for removed settings", ex.getMessage()); } } } diff --git a/core/src/test/java/org/elasticsearch/discovery/DiscoveryModuleTests.java b/core/src/test/java/org/elasticsearch/discovery/DiscoveryModuleTests.java index 00ed8a2673c..86c3cd91bff 100644 --- a/core/src/test/java/org/elasticsearch/discovery/DiscoveryModuleTests.java +++ b/core/src/test/java/org/elasticsearch/discovery/DiscoveryModuleTests.java @@ -33,8 +33,8 @@ public class DiscoveryModuleTests extends ModuleTestCase { public static class DummyMasterElectionService extends ElectMasterService { - public DummyMasterElectionService(Settings settings, Version version) { - super(settings, version); + public DummyMasterElectionService(Settings settings) { + super(settings); } } diff --git a/core/src/test/java/org/elasticsearch/discovery/ZenFaultDetectionTests.java b/core/src/test/java/org/elasticsearch/discovery/ZenFaultDetectionTests.java index 90a3a2e8c1e..c6e55ac9181 100644 --- a/core/src/test/java/org/elasticsearch/discovery/ZenFaultDetectionTests.java +++ b/core/src/test/java/org/elasticsearch/discovery/ZenFaultDetectionTests.java @@ -141,7 +141,12 @@ public class ZenFaultDetectionTests extends ESTestCase { // trace zenfd actions but keep the default otherwise .put(TransportService.TRACE_LOG_EXCLUDE_SETTING.getKey(), singleton(TransportLivenessAction.NAME)) .build(), - new LocalTransport(settings, threadPool, version, namedWriteableRegistry, circuitBreakerService), + new LocalTransport(settings, threadPool, namedWriteableRegistry, circuitBreakerService) { + @Override + protected Version getVersion() { + return version; + } + }, threadPool); transportService.start(); transportService.acceptIncomingRequests(); diff --git a/core/src/test/java/org/elasticsearch/discovery/zen/ElectMasterServiceTests.java b/core/src/test/java/org/elasticsearch/discovery/zen/ElectMasterServiceTests.java index 498aff28ee6..0f93e5d460c 100644 --- a/core/src/test/java/org/elasticsearch/discovery/zen/ElectMasterServiceTests.java +++ b/core/src/test/java/org/elasticsearch/discovery/zen/ElectMasterServiceTests.java @@ -35,15 +35,12 @@ import java.util.Set; public class ElectMasterServiceTests extends ESTestCase { ElectMasterService electMasterService() { - return new ElectMasterService(Settings.EMPTY, Version.CURRENT); + return new ElectMasterService(Settings.EMPTY); } List generateRandomNodes() { int count = scaledRandomIntBetween(1, 100); ArrayList nodes = new ArrayList<>(count); - - - for (int i = 0; i < count; i++) { Set roles = new HashSet<>(); if (randomBoolean()) { diff --git a/core/src/test/java/org/elasticsearch/discovery/zen/NodeJoinControllerTests.java b/core/src/test/java/org/elasticsearch/discovery/zen/NodeJoinControllerTests.java index 683bebc55a3..e994c376c4d 100644 --- a/core/src/test/java/org/elasticsearch/discovery/zen/NodeJoinControllerTests.java +++ b/core/src/test/java/org/elasticsearch/discovery/zen/NodeJoinControllerTests.java @@ -99,7 +99,7 @@ public class NodeJoinControllerTests extends ESTestCase { setState(clusterService, ClusterState.builder(clusterService.state()).nodes( DiscoveryNodes.builder(initialNodes).masterNodeId(localNode.getId()))); nodeJoinController = new NodeJoinController(clusterService, new NoopAllocationService(Settings.EMPTY), - new ElectMasterService(Settings.EMPTY, Version.CURRENT), + new ElectMasterService(Settings.EMPTY), new DiscoverySettings(Settings.EMPTY, new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS)), Settings.EMPTY); } diff --git a/core/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryIT.java b/core/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryIT.java index d12a0ff55a3..c5f92e62de0 100644 --- a/core/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryIT.java +++ b/core/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryIT.java @@ -320,7 +320,7 @@ public class ZenDiscoveryIT extends ESIntegTestCase { } public void testJoinElectedMaster_incompatibleMinVersion() { - ElectMasterService electMasterService = new ElectMasterService(Settings.EMPTY, Version.CURRENT); + ElectMasterService electMasterService = new ElectMasterService(Settings.EMPTY); DiscoveryNode node = new DiscoveryNode("_node_id", new LocalTransportAddress("_id"), emptyMap(), Collections.singleton(DiscoveryNode.Role.MASTER), Version.CURRENT); diff --git a/core/src/test/java/org/elasticsearch/discovery/zen/ping/unicast/UnicastZenPingIT.java b/core/src/test/java/org/elasticsearch/discovery/zen/ping/unicast/UnicastZenPingIT.java index 11816512583..f072c5faf8a 100644 --- a/core/src/test/java/org/elasticsearch/discovery/zen/ping/unicast/UnicastZenPingIT.java +++ b/core/src/test/java/org/elasticsearch/discovery/zen/ping/unicast/UnicastZenPingIT.java @@ -68,7 +68,7 @@ public class UnicastZenPingIT extends ESTestCase { ThreadPool threadPool = new TestThreadPool(getClass().getName()); NetworkService networkService = new NetworkService(settings); - ElectMasterService electMasterService = new ElectMasterService(settings, Version.CURRENT); + ElectMasterService electMasterService = new ElectMasterService(settings); NetworkHandle handleA = startServices(settings, threadPool, networkService, "UZP_A", Version.CURRENT); NetworkHandle handleB = startServices(settings, threadPool, networkService, "UZP_B", Version.CURRENT); @@ -88,7 +88,7 @@ public class UnicastZenPingIT extends ESTestCase { .build(); Settings hostsSettingsMismatch = Settings.builder().put(hostsSettings).put(settingsMismatch).build(); - UnicastZenPing zenPingA = new UnicastZenPing(hostsSettings, threadPool, handleA.transportService, Version.CURRENT, electMasterService, null); + UnicastZenPing zenPingA = new UnicastZenPing(hostsSettings, threadPool, handleA.transportService, electMasterService, null); zenPingA.setPingContextProvider(new PingContextProvider() { @Override public DiscoveryNodes nodes() { @@ -102,7 +102,7 @@ public class UnicastZenPingIT extends ESTestCase { }); zenPingA.start(); - UnicastZenPing zenPingB = new UnicastZenPing(hostsSettings, threadPool, handleB.transportService, Version.CURRENT, electMasterService, null); + UnicastZenPing zenPingB = new UnicastZenPing(hostsSettings, threadPool, handleB.transportService, electMasterService, null); zenPingB.setPingContextProvider(new PingContextProvider() { @Override public DiscoveryNodes nodes() { @@ -116,7 +116,13 @@ public class UnicastZenPingIT extends ESTestCase { }); zenPingB.start(); - UnicastZenPing zenPingC = new UnicastZenPing(hostsSettingsMismatch, threadPool, handleC.transportService, versionD, electMasterService, null); + UnicastZenPing zenPingC = new UnicastZenPing(hostsSettingsMismatch, threadPool, handleC.transportService, electMasterService, + null) { + @Override + protected Version getVersion() { + return versionD; + } + }; zenPingC.setPingContextProvider(new PingContextProvider() { @Override public DiscoveryNodes nodes() { @@ -130,7 +136,7 @@ public class UnicastZenPingIT extends ESTestCase { }); zenPingC.start(); - UnicastZenPing zenPingD = new UnicastZenPing(hostsSettingsMismatch, threadPool, handleD.transportService, Version.CURRENT, electMasterService, null); + UnicastZenPing zenPingD = new UnicastZenPing(hostsSettingsMismatch, threadPool, handleD.transportService, electMasterService, null); zenPingD.setPingContextProvider(new PingContextProvider() { @Override public DiscoveryNodes nodes() { @@ -191,8 +197,15 @@ public class UnicastZenPingIT extends ESTestCase { } } - private NetworkHandle startServices(Settings settings, ThreadPool threadPool, NetworkService networkService, String nodeId, Version version) { - NettyTransport transport = new NettyTransport(settings, threadPool, networkService, BigArrays.NON_RECYCLING_INSTANCE, version, new NamedWriteableRegistry(), new NoneCircuitBreakerService()); + private NetworkHandle startServices(Settings settings, ThreadPool threadPool, NetworkService networkService, String nodeId, + Version version) { + NettyTransport transport = new NettyTransport(settings, threadPool, networkService, BigArrays.NON_RECYCLING_INSTANCE, + new NamedWriteableRegistry(), new NoneCircuitBreakerService()) { + @Override + protected Version getCurrentVersion() { + return version; + } + }; final TransportService transportService = new TransportService(settings, transport, threadPool); transportService.start(); transportService.acceptIncomingRequests(); @@ -208,7 +221,8 @@ public class UnicastZenPingIT extends ESTestCase { public void onNodeDisconnected(DiscoveryNode node) { } }); - final DiscoveryNode node = new DiscoveryNode(nodeId, transportService.boundAddress().publishAddress(), emptyMap(), emptySet(), version); + final DiscoveryNode node = new DiscoveryNode(nodeId, transportService.boundAddress().publishAddress(), emptyMap(), emptySet(), + version); transportService.setLocalNode(node); return new NetworkHandle((InetSocketTransportAddress)transport.boundAddress().publishAddress(), transportService, node, counters); } @@ -219,7 +233,8 @@ public class UnicastZenPingIT extends ESTestCase { public final DiscoveryNode node; public final ConcurrentMap counters; - public NetworkHandle(InetSocketTransportAddress address, TransportService transportService, DiscoveryNode discoveryNode, ConcurrentMap counters) { + public NetworkHandle(InetSocketTransportAddress address, TransportService transportService, DiscoveryNode discoveryNode, + ConcurrentMap counters) { this.address = address; this.transportService = transportService; this.node = discoveryNode; diff --git a/core/src/test/java/org/elasticsearch/discovery/zen/publish/PublishClusterStateActionTests.java b/core/src/test/java/org/elasticsearch/discovery/zen/publish/PublishClusterStateActionTests.java index ed09efaaada..61374cc0d8f 100644 --- a/core/src/test/java/org/elasticsearch/discovery/zen/publish/PublishClusterStateActionTests.java +++ b/core/src/test/java/org/elasticsearch/discovery/zen/publish/PublishClusterStateActionTests.java @@ -145,26 +145,22 @@ public class PublishClusterStateActionTests extends ESTestCase { } public MockNode createMockNode(final String name) throws Exception { - return createMockNode(name, Settings.EMPTY, Version.CURRENT); + return createMockNode(name, Settings.EMPTY); } public MockNode createMockNode(String name, Settings settings) throws Exception { - return createMockNode(name, settings, Version.CURRENT); + return createMockNode(name, settings, null); } - public MockNode createMockNode(final String name, Settings settings, Version version) throws Exception { - return createMockNode(name, settings, version, null); - } - - public MockNode createMockNode(String name, Settings settings, Version version, @Nullable ClusterStateListener listener) throws Exception { + public MockNode createMockNode(String name, Settings settings, @Nullable ClusterStateListener listener) throws Exception { settings = Settings.builder() .put("name", name) .put(TransportService.TRACE_LOG_INCLUDE_SETTING.getKey(), "", TransportService.TRACE_LOG_EXCLUDE_SETTING.getKey(), "NOTHING") .put(settings) .build(); - MockTransportService service = buildTransportService(settings, version); - DiscoveryNodeService discoveryNodeService = new DiscoveryNodeService(settings, version); + MockTransportService service = buildTransportService(settings); + DiscoveryNodeService discoveryNodeService = new DiscoveryNodeService(settings); DiscoveryNode discoveryNode = discoveryNodeService.buildLocalNode(service.boundAddress().publishAddress()); MockNode node = new MockNode(discoveryNode, service, listener, logger); node.action = buildPublishClusterStateAction(settings, service, () -> node.clusterState, node); @@ -232,8 +228,8 @@ public class PublishClusterStateActionTests extends ESTestCase { terminate(threadPool); } - protected MockTransportService buildTransportService(Settings settings, Version version) { - MockTransportService transportService = MockTransportService.local(Settings.EMPTY, version, threadPool); + protected MockTransportService buildTransportService(Settings settings) { + MockTransportService transportService = MockTransportService.local(Settings.EMPTY, Version.CURRENT, threadPool); transportService.start(); transportService.acceptIncomingRequests(); return transportService; @@ -257,8 +253,8 @@ public class PublishClusterStateActionTests extends ESTestCase { } public void testSimpleClusterStatePublishing() throws Exception { - MockNode nodeA = createMockNode("nodeA", Settings.EMPTY, Version.CURRENT).setAsMaster(); - MockNode nodeB = createMockNode("nodeB", Settings.EMPTY, Version.CURRENT); + MockNode nodeA = createMockNode("nodeA", Settings.EMPTY).setAsMaster(); + MockNode nodeB = createMockNode("nodeB", Settings.EMPTY); // Initial cluster state ClusterState clusterState = nodeA.clusterState; @@ -286,7 +282,7 @@ public class PublishClusterStateActionTests extends ESTestCase { // Adding new node - this node should get full cluster state while nodeB should still be getting diffs - MockNode nodeC = createMockNode("nodeC", Settings.EMPTY, Version.CURRENT); + MockNode nodeC = createMockNode("nodeC", Settings.EMPTY); // cluster state update 3 - register node C previousClusterState = clusterState; @@ -336,14 +332,11 @@ public class PublishClusterStateActionTests extends ESTestCase { } public void testUnexpectedDiffPublishing() throws Exception { - MockNode nodeA = createMockNode("nodeA", Settings.EMPTY, Version.CURRENT, new ClusterStateListener() { - @Override - public void clusterChanged(ClusterChangedEvent event) { - fail("Shouldn't send cluster state to myself"); - } + MockNode nodeA = createMockNode("nodeA", Settings.EMPTY, event -> { + fail("Shouldn't send cluster state to myself"); }).setAsMaster(); - MockNode nodeB = createMockNode("nodeB", Settings.EMPTY, Version.CURRENT); + MockNode nodeB = createMockNode("nodeB", Settings.EMPTY); // Initial cluster state with both states - the second node still shouldn't get diff even though it's present in the previous cluster state DiscoveryNodes discoveryNodes = DiscoveryNodes.builder(nodeA.nodes()).put(nodeB.discoveryNode).build(); @@ -362,14 +355,14 @@ public class PublishClusterStateActionTests extends ESTestCase { public void testDisablingDiffPublishing() throws Exception { Settings noDiffPublishingSettings = Settings.builder().put(DiscoverySettings.PUBLISH_DIFF_ENABLE_SETTING.getKey(), false).build(); - MockNode nodeA = createMockNode("nodeA", noDiffPublishingSettings, Version.CURRENT, new ClusterStateListener() { + MockNode nodeA = createMockNode("nodeA", noDiffPublishingSettings, new ClusterStateListener() { @Override public void clusterChanged(ClusterChangedEvent event) { fail("Shouldn't send cluster state to myself"); } }); - MockNode nodeB = createMockNode("nodeB", noDiffPublishingSettings, Version.CURRENT, new ClusterStateListener() { + MockNode nodeB = createMockNode("nodeB", noDiffPublishingSettings, new ClusterStateListener() { @Override public void clusterChanged(ClusterChangedEvent event) { assertFalse(event.state().wasReadFromDiff()); @@ -400,7 +393,7 @@ public class PublishClusterStateActionTests extends ESTestCase { int numberOfNodes = randomIntBetween(2, 10); int numberOfIterations = scaledRandomIntBetween(5, 50); Settings settings = Settings.builder().put(DiscoverySettings.PUBLISH_DIFF_ENABLE_SETTING.getKey(), randomBoolean()).build(); - MockNode master = createMockNode("node0", settings, Version.CURRENT, new ClusterStateListener() { + MockNode master = createMockNode("node0", settings, new ClusterStateListener() { @Override public void clusterChanged(ClusterChangedEvent event) { assertProperMetaDataForVersion(event.state().metaData(), event.state().version()); @@ -409,7 +402,7 @@ public class PublishClusterStateActionTests extends ESTestCase { DiscoveryNodes.Builder discoveryNodesBuilder = DiscoveryNodes.builder(master.nodes()); for (int i = 1; i < numberOfNodes; i++) { final String name = "node" + i; - final MockNode node = createMockNode(name, settings, Version.CURRENT, new ClusterStateListener() { + final MockNode node = createMockNode(name, settings, new ClusterStateListener() { @Override public void clusterChanged(ClusterChangedEvent event) { assertProperMetaDataForVersion(event.state().metaData(), event.state().version()); @@ -444,14 +437,14 @@ public class PublishClusterStateActionTests extends ESTestCase { } public void testSerializationFailureDuringDiffPublishing() throws Exception { - MockNode nodeA = createMockNode("nodeA", Settings.EMPTY, Version.CURRENT, new ClusterStateListener() { + MockNode nodeA = createMockNode("nodeA", Settings.EMPTY, new ClusterStateListener() { @Override public void clusterChanged(ClusterChangedEvent event) { fail("Shouldn't send cluster state to myself"); } }).setAsMaster(); - MockNode nodeB = createMockNode("nodeB", Settings.EMPTY, Version.CURRENT); + MockNode nodeB = createMockNode("nodeB", Settings.EMPTY); // Initial cluster state with both states - the second node still shouldn't get diff even though it's present in the previous cluster state DiscoveryNodes discoveryNodes = DiscoveryNodes.builder(nodeA.nodes()).put(nodeB.discoveryNode).build(); diff --git a/core/src/test/java/org/elasticsearch/http/HttpServerTests.java b/core/src/test/java/org/elasticsearch/http/HttpServerTests.java index 32f9bbbd84c..2ba7da84c14 100644 --- a/core/src/test/java/org/elasticsearch/http/HttpServerTests.java +++ b/core/src/test/java/org/elasticsearch/http/HttpServerTests.java @@ -74,7 +74,7 @@ public class HttpServerTests extends ESTestCase { ClusterService clusterService = new ClusterService(Settings.EMPTY, new ClusterSettings(settings, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS), null); - NodeService nodeService = new NodeService(Settings.EMPTY, null, null, null, null, null, null, null, null, null, + NodeService nodeService = new NodeService(Settings.EMPTY, null, null, null, null, null, null, null, null, clusterService, null); httpServer = new HttpServer(settings, httpServerTransport, restController, nodeService, circuitBreakerService); httpServer.start(); diff --git a/core/src/test/java/org/elasticsearch/index/mapper/DynamicMappingDisabledTests.java b/core/src/test/java/org/elasticsearch/index/mapper/DynamicMappingDisabledTests.java index cc8b05819c6..f9fb5e77b70 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/DynamicMappingDisabledTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/DynamicMappingDisabledTests.java @@ -76,7 +76,7 @@ public class DynamicMappingDisabledTests extends ESSingleNodeTestCase { .build(); clusterService = createClusterService(THREAD_POOL); transport = - new LocalTransport(settings, THREAD_POOL, Version.CURRENT, new NamedWriteableRegistry(), new NoneCircuitBreakerService()); + new LocalTransport(settings, THREAD_POOL, new NamedWriteableRegistry(), new NoneCircuitBreakerService()); transportService = new TransportService(clusterService.getSettings(), transport, THREAD_POOL); indicesService = getInstanceFromNode(IndicesService.class); shardStateAction = new ShardStateAction(settings, clusterService, transportService, null, null, THREAD_POOL); diff --git a/core/src/test/java/org/elasticsearch/index/store/FsDirectoryServiceTests.java b/core/src/test/java/org/elasticsearch/index/store/FsDirectoryServiceTests.java index f7d793f03ed..6042d471717 100644 --- a/core/src/test/java/org/elasticsearch/index/store/FsDirectoryServiceTests.java +++ b/core/src/test/java/org/elasticsearch/index/store/FsDirectoryServiceTests.java @@ -19,13 +19,13 @@ package org.elasticsearch.index.store; import org.apache.lucene.store.Directory; -import org.apache.lucene.store.FilterDirectory; +import org.apache.lucene.store.FileSwitchDirectory; +import org.apache.lucene.store.MMapDirectory; import org.apache.lucene.store.RateLimitedFSDirectory; import org.apache.lucene.store.SimpleFSDirectory; import org.apache.lucene.store.SleepingLockWrapper; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.shard.ShardId; @@ -36,6 +36,7 @@ import org.elasticsearch.test.IndexSettingsModule; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; public class FsDirectoryServiceTests extends ESTestCase { @@ -73,4 +74,43 @@ public class FsDirectoryServiceTests extends ESTestCase { assertFalse(delegate instanceof SleepingLockWrapper); assertTrue(delegate instanceof SimpleFSDirectory); } + + public void testPreload() throws IOException { + doTestPreload(); + doTestPreload("nvd", "dvd", "tim"); + doTestPreload("*"); + } + + private void doTestPreload(String...preload) throws IOException { + Settings build = Settings.builder() + .put(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), "mmapfs") + .putArray(IndexModule.INDEX_STORE_PRE_LOAD_SETTING.getKey(), preload) + .build(); + IndexSettings settings = IndexSettingsModule.newIndexSettings("foo", build); + IndexStoreConfig config = new IndexStoreConfig(settings.getSettings()); + IndexStore store = new IndexStore(settings, config); + Path tempDir = createTempDir().resolve(settings.getUUID()).resolve("0"); + Files.createDirectories(tempDir); + ShardPath path = new ShardPath(false, tempDir, tempDir, new ShardId(settings.getIndex(), 0)); + FsDirectoryService fsDirectoryService = new FsDirectoryService(settings, store, path); + Directory directory = fsDirectoryService.newDirectory(); + assertTrue(directory instanceof RateLimitedFSDirectory); + RateLimitedFSDirectory rateLimitingDirectory = (RateLimitedFSDirectory) directory; + Directory delegate = rateLimitingDirectory.getDelegate(); + assertFalse(delegate instanceof SleepingLockWrapper); + if (preload.length == 0) { + assertTrue(delegate.toString(), delegate instanceof MMapDirectory); + assertFalse(((MMapDirectory) delegate).getPreload()); + } else if (Arrays.asList(preload).contains("*")) { + assertTrue(delegate.toString(), delegate instanceof MMapDirectory); + assertTrue(((MMapDirectory) delegate).getPreload()); + } else { + assertTrue(delegate.toString(), delegate instanceof FileSwitchDirectory); + FileSwitchDirectory fsd = (FileSwitchDirectory) delegate; + assertTrue(fsd.getPrimaryDir() instanceof MMapDirectory); + assertTrue(((MMapDirectory) fsd.getPrimaryDir()).getPreload()); + assertTrue(fsd.getSecondaryDir() instanceof MMapDirectory); + assertFalse(((MMapDirectory) fsd.getSecondaryDir()).getPreload()); + } + } } diff --git a/core/src/test/java/org/elasticsearch/index/store/IndexStoreTests.java b/core/src/test/java/org/elasticsearch/index/store/IndexStoreTests.java index 0e012f0d1a7..fe5410ccaf8 100644 --- a/core/src/test/java/org/elasticsearch/index/store/IndexStoreTests.java +++ b/core/src/test/java/org/elasticsearch/index/store/IndexStoreTests.java @@ -77,6 +77,7 @@ public class IndexStoreTests extends ESTestCase { assertTrue(type + " " + directory.toString(), directory instanceof SimpleFSDirectory); break; case FS: + case DEFAULT: if (Constants.JRE_IS_64BIT && MMapDirectory.UNMAP_SUPPORTED) { assertTrue(directory.toString(), directory instanceof MMapDirectory); } else if (Constants.WINDOWS) { @@ -85,19 +86,6 @@ public class IndexStoreTests extends ESTestCase { assertTrue(directory.toString(), directory instanceof NIOFSDirectory); } break; - case DEFAULT: - if (Constants.WINDOWS) { - if (Constants.JRE_IS_64BIT && MMapDirectory.UNMAP_SUPPORTED) { - assertTrue(type + " " + directory.toString(), directory instanceof MMapDirectory); - } else { - assertTrue(type + " " + directory.toString(), directory instanceof SimpleFSDirectory); - } - } else if (Constants.JRE_IS_64BIT && MMapDirectory.UNMAP_SUPPORTED) { - assertTrue(type + " " + directory.toString(), directory instanceof FileSwitchDirectory); - } else { - assertTrue(type + " " + directory.toString(), directory instanceof NIOFSDirectory); - } - break; default: fail(); } diff --git a/core/src/test/java/org/elasticsearch/indices/cluster/ClusterStateChanges.java b/core/src/test/java/org/elasticsearch/indices/cluster/ClusterStateChanges.java index 86d19ae1ea4..fc5b68f87d1 100644 --- a/core/src/test/java/org/elasticsearch/indices/cluster/ClusterStateChanges.java +++ b/core/src/test/java/org/elasticsearch/indices/cluster/ClusterStateChanges.java @@ -158,7 +158,7 @@ public class ClusterStateChanges { MetaDataUpdateSettingsService metaDataUpdateSettingsService = new MetaDataUpdateSettingsService(settings, clusterService, allocationService, IndexScopedSettings.DEFAULT_SCOPED_SETTINGS, new IndexNameExpressionResolver(settings)); MetaDataCreateIndexService createIndexService = new MetaDataCreateIndexService(settings, clusterService, indicesService, - allocationService, Version.CURRENT, new AliasValidator(settings), Collections.emptySet(), environment, + allocationService, new AliasValidator(settings), Collections.emptySet(), environment, nodeServicesProvider, IndexScopedSettings.DEFAULT_SCOPED_SETTINGS); transportCloseIndexAction = new TransportCloseIndexAction(settings, transportService, clusterService, threadPool, diff --git a/core/src/test/java/org/elasticsearch/indices/state/SimpleIndexStateIT.java b/core/src/test/java/org/elasticsearch/indices/state/SimpleIndexStateIT.java index f3898bc9f3c..ea3ebf5179b 100644 --- a/core/src/test/java/org/elasticsearch/indices/state/SimpleIndexStateIT.java +++ b/core/src/test/java/org/elasticsearch/indices/state/SimpleIndexStateIT.java @@ -56,7 +56,8 @@ public class SimpleIndexStateIT extends ESIntegTestCase { ClusterStateResponse stateResponse = client().admin().cluster().prepareState().get(); assertThat(stateResponse.getState().metaData().index("test").getState(), equalTo(IndexMetaData.State.OPEN)); assertThat(stateResponse.getState().routingTable().index("test").shards().size(), equalTo(numShards.numPrimaries)); - assertThat(stateResponse.getState().routingTable().index("test").shardsWithState(ShardRoutingState.STARTED).size(), equalTo(numShards.totalNumShards)); + assertEquals(stateResponse.getState().routingTable().index("test").shardsWithState(ShardRoutingState.STARTED).size() + , numShards.totalNumShards); logger.info("--> indexing a simple document"); client().prepareIndex("test", "type1", "1").setSource("field1", "value1").get(); @@ -88,7 +89,8 @@ public class SimpleIndexStateIT extends ESIntegTestCase { assertThat(stateResponse.getState().metaData().index("test").getState(), equalTo(IndexMetaData.State.OPEN)); assertThat(stateResponse.getState().routingTable().index("test").shards().size(), equalTo(numShards.numPrimaries)); - assertThat(stateResponse.getState().routingTable().index("test").shardsWithState(ShardRoutingState.STARTED).size(), equalTo(numShards.totalNumShards)); + assertEquals(stateResponse.getState().routingTable().index("test").shardsWithState(ShardRoutingState.STARTED).size(), + numShards.totalNumShards); logger.info("--> indexing a simple document"); client().prepareIndex("test", "type1", "1").setSource("field1", "value1").get(); @@ -119,7 +121,8 @@ public class SimpleIndexStateIT extends ESIntegTestCase { ClusterStateResponse stateResponse = client().admin().cluster().prepareState().get(); assertThat(stateResponse.getState().metaData().index("test").getState(), equalTo(IndexMetaData.State.OPEN)); assertThat(stateResponse.getState().routingTable().index("test").shards().size(), equalTo(numShards.numPrimaries)); - assertThat(stateResponse.getState().routingTable().index("test").shardsWithState(ShardRoutingState.STARTED).size(), equalTo(numShards.totalNumShards)); + assertEquals(stateResponse.getState().routingTable().index("test").shardsWithState(ShardRoutingState.STARTED).size(), + numShards.totalNumShards); logger.info("--> indexing a simple document"); client().prepareIndex("test", "type1", "1").setSource("field1", "value1").get(); @@ -143,7 +146,8 @@ public class SimpleIndexStateIT extends ESIntegTestCase { } logger.info("--> creating test index with valid settings "); - CreateIndexResponse response = client().admin().indices().prepareCreate("test").setSettings(Settings.builder().put("number_of_shards", 1)).get(); + CreateIndexResponse response = client().admin().indices().prepareCreate("test") + .setSettings(Settings.builder().put("number_of_shards", 1)).get(); assertThat(response.isAcknowledged(), equalTo(true)); } } diff --git a/core/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateIT.java b/core/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateIT.java index 298cb9cd9e3..493f8b74e04 100644 --- a/core/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateIT.java +++ b/core/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateIT.java @@ -322,7 +322,8 @@ public class SimpleIndexTemplateIT extends ESIntegTestCase { .setTemplate("te*") .setSettings(Settings.builder().put("does_not_exist", "test")) .get()); - assertEquals("unknown setting [index.does_not_exist]", e.getMessage()); + assertEquals("unknown setting [index.does_not_exist] please check that any required plugins are" + + " installed, or check the breaking changes documentation for removed settings", e.getMessage()); response = client().admin().indices().prepareGetTemplates().get(); assertEquals(0, response.getIndexTemplates().size()); diff --git a/core/src/test/java/org/elasticsearch/script/NativeScriptTests.java b/core/src/test/java/org/elasticsearch/script/NativeScriptTests.java index 65c0a4fddef..d88813203b2 100644 --- a/core/src/test/java/org/elasticsearch/script/NativeScriptTests.java +++ b/core/src/test/java/org/elasticsearch/script/NativeScriptTests.java @@ -28,7 +28,6 @@ import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsModule; import org.elasticsearch.env.Environment; -import org.elasticsearch.env.EnvironmentModule; import org.elasticsearch.script.ScriptService.ScriptType; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.InternalSettingsPlugin; @@ -41,9 +40,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; -import static java.util.Collections.singleton; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.notNullValue; @@ -60,7 +57,10 @@ public class NativeScriptTests extends ESTestCase { SettingsModule settingsModule = new SettingsModule(settings, scriptSettings, Collections.emptyList()); final ThreadPool threadPool = new ThreadPool(settings); Injector injector = new ModulesBuilder().add( - new EnvironmentModule(new Environment(settings), threadPool), + (b) -> { + b.bind(Environment.class).toInstance(new Environment(settings)); + b.bind(ThreadPool.class).toInstance(threadPool); + }, new SettingsModule(settings), scriptModule).createInjector(); diff --git a/core/src/test/java/org/elasticsearch/script/ScriptModesTests.java b/core/src/test/java/org/elasticsearch/script/ScriptModesTests.java index 2927b4747dc..e4a1835ab63 100644 --- a/core/src/test/java/org/elasticsearch/script/ScriptModesTests.java +++ b/core/src/test/java/org/elasticsearch/script/ScriptModesTests.java @@ -257,12 +257,6 @@ public class ScriptModesTests extends ESTestCase { @Override public void close() { - - } - - @Override - public void scriptRemoved(@Nullable CompiledScript script) { - } } } diff --git a/core/src/test/java/org/elasticsearch/script/ScriptServiceTests.java b/core/src/test/java/org/elasticsearch/script/ScriptServiceTests.java index db9e7d66731..597cb7e6032 100644 --- a/core/src/test/java/org/elasticsearch/script/ScriptServiceTests.java +++ b/core/src/test/java/org/elasticsearch/script/ScriptServiceTests.java @@ -518,11 +518,6 @@ public class ScriptServiceTests extends ESTestCase { } - @Override - public void scriptRemoved(CompiledScript script) { - // Nothing to do here - } - @Override public boolean isInlineScriptEnabled() { return true; @@ -562,12 +557,6 @@ public class ScriptServiceTests extends ESTestCase { @Override public void close() { - - } - - @Override - public void scriptRemoved(CompiledScript script) { - // Nothing to do here } } diff --git a/core/src/test/java/org/elasticsearch/script/ScriptSettingsTests.java b/core/src/test/java/org/elasticsearch/script/ScriptSettingsTests.java index 0e2bb384152..053ccec652c 100644 --- a/core/src/test/java/org/elasticsearch/script/ScriptSettingsTests.java +++ b/core/src/test/java/org/elasticsearch/script/ScriptSettingsTests.java @@ -95,12 +95,6 @@ public class ScriptSettingsTests extends ESTestCase { @Override public void close() { - - } - - @Override - public void scriptRemoved(@Nullable CompiledScript script) { - } } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/AggregatorParsingTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/AggregatorParsingTests.java index 5dd321bdf07..a78c405929a 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/AggregatorParsingTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/AggregatorParsingTests.java @@ -38,7 +38,6 @@ import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.env.Environment; -import org.elasticsearch.env.EnvironmentModule; import org.elasticsearch.index.Index; import org.elasticsearch.test.AbstractQueryTestCase; import org.elasticsearch.index.query.QueryParseContext; @@ -109,7 +108,11 @@ public class AggregatorParsingTests extends ESTestCase { List> scriptSettings = scriptModule.getSettings(); scriptSettings.add(InternalSettingsPlugin.VERSION_CREATED); SettingsModule settingsModule = new SettingsModule(settings, scriptSettings, Collections.emptyList()); - injector = new ModulesBuilder().add(new EnvironmentModule(new Environment(settings), threadPool), settingsModule + injector = new ModulesBuilder().add( + (b) -> { + b.bind(Environment.class).toInstance(new Environment(settings)); + b.bind(ThreadPool.class).toInstance(threadPool); + }, settingsModule , scriptModule, new IndicesModule(namedWriteableRegistry) { @Override diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java b/core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java index c7d1084067a..7bce599f55a 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java @@ -42,7 +42,6 @@ import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.env.Environment; -import org.elasticsearch.env.EnvironmentModule; import org.elasticsearch.index.Index; import org.elasticsearch.test.AbstractQueryTestCase; import org.elasticsearch.index.query.QueryParseContext; @@ -103,53 +102,9 @@ public abstract class BaseAggregationTestCase> scriptSettings = scriptModule.getSettings(); - scriptSettings.add(InternalSettingsPlugin.VERSION_CREATED); - SettingsModule settingsModule = new SettingsModule(settings, scriptSettings, Collections.emptyList()); - injector = new ModulesBuilder().add( - new EnvironmentModule(new Environment(settings), threadPool), - settingsModule, - scriptModule, - new IndicesModule(namedWriteableRegistry) { - - @Override - protected void configure() { - bindMapperExtension(); - } - }, new SearchModule(settings, namedWriteableRegistry) { - @Override - protected void configureSearch() { - // Skip me - } - }, - new IndexSettingsModule(index, settings), - - new AbstractModule() { - @Override - protected void configure() { - bind(ClusterService.class).toProvider(Providers.of(clusterService)); - bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class); - bind(NamedWriteableRegistry.class).toInstance(namedWriteableRegistry); - } - } - ).createInjector(); + injector = buildInjector(index); + namedWriteableRegistry = injector.getInstance(NamedWriteableRegistry.class); aggParsers = injector.getInstance(AggregatorParsers.class); //create some random type with some default field, those types will stick around for all of the subclasses currentTypes = new String[randomIntBetween(0, 5)]; @@ -161,6 +116,59 @@ public abstract class BaseAggregationTestCase> scriptSettings = scriptModule.getSettings(); + scriptSettings.add(InternalSettingsPlugin.VERSION_CREATED); + SettingsModule settingsModule = new SettingsModule(settings, scriptSettings, Collections.emptyList()); + return new ModulesBuilder().add( + (b) -> { + b.bind(Environment.class).toInstance(new Environment(settings)); + b.bind(ThreadPool.class).toInstance(threadPool); + }, + settingsModule, + scriptModule, + new IndicesModule(namedWriteableRegistry) { + + @Override + protected void configure() { + bindMapperExtension(); + } + }, new SearchModule(settings, namedWriteableRegistry) { + @Override + protected void configureSearch() { + // Skip me + } + }, + new IndexSettingsModule(index, settings), + + new AbstractModule() { + @Override + protected void configure() { + bind(ClusterService.class).toProvider(Providers.of(clusterService)); + bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class); + bind(NamedWriteableRegistry.class).toInstance(namedWriteableRegistry); + } + } + ).createInjector(); + } + + @AfterClass public static void afterClass() throws Exception { injector.getInstance(ClusterService.class).close(); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java b/core/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java index a907e75d5f7..a3f9f11dc2e 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java @@ -19,55 +19,29 @@ package org.elasticsearch.search.aggregations; -import org.elasticsearch.Version; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.ParseFieldMatcher; -import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.Injector; -import org.elasticsearch.common.inject.ModulesBuilder; -import org.elasticsearch.common.inject.util.Providers; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.settings.Setting; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.settings.SettingsModule; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; -import org.elasticsearch.env.Environment; -import org.elasticsearch.env.EnvironmentModule; import org.elasticsearch.index.Index; import org.elasticsearch.index.query.QueryParseContext; -import org.elasticsearch.indices.IndicesModule; -import org.elasticsearch.indices.breaker.CircuitBreakerService; -import org.elasticsearch.indices.breaker.NoneCircuitBreakerService; import org.elasticsearch.indices.query.IndicesQueriesRegistry; -import org.elasticsearch.script.ScriptModule; -import org.elasticsearch.script.ScriptService; -import org.elasticsearch.search.SearchModule; import org.elasticsearch.search.aggregations.pipeline.AbstractPipelineAggregationBuilder; -import org.elasticsearch.test.AbstractQueryTestCase; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.test.IndexSettingsModule; -import org.elasticsearch.test.InternalSettingsPlugin; -import org.elasticsearch.test.VersionUtils; import org.elasticsearch.threadpool.ThreadPool; import org.junit.AfterClass; import org.junit.BeforeClass; import java.io.IOException; -import java.util.Collections; -import java.util.List; - -import static org.elasticsearch.test.ClusterServiceUtils.createClusterService; -import static org.elasticsearch.test.ClusterServiceUtils.setState; import static org.hamcrest.Matchers.equalTo; public abstract class BasePipelineAggregationTestCase> extends ESTestCase { @@ -77,9 +51,6 @@ public abstract class BasePipelineAggregationTestCase> scriptSettings = scriptModule.getSettings(); - scriptSettings.add(InternalSettingsPlugin.VERSION_CREATED); - SettingsModule settingsModule = new SettingsModule(settings, scriptSettings, Collections.emptyList()); - injector = new ModulesBuilder().add( - new EnvironmentModule(new Environment(settings),threadPool), - settingsModule, - scriptModule, - new IndicesModule(namedWriteableRegistry) { - - @Override - protected void configure() { - bindMapperExtension(); - } - }, new SearchModule(settings, namedWriteableRegistry) { - @Override - protected void configureSearch() { - // Skip me - } - }, - new IndexSettingsModule(index, settings), - new AbstractModule() { - @Override - protected void configure() { - bind(ClusterService.class).toProvider(Providers.of(clusterService)); - bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class); - bind(NamedWriteableRegistry.class).toInstance(namedWriteableRegistry); - } - } - ).createInjector(); + injector = BaseAggregationTestCase.buildInjector(index); + namedWriteableRegistry = injector.getInstance(NamedWriteableRegistry.class); aggParsers = injector.getInstance(AggregatorParsers.class); //create some random type with some default field, those types will stick around for all of the subclasses currentTypes = new String[randomIntBetween(0, 5)]; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgIT.java index ad2c0ddb9d5..ccf03df37fc 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgIT.java @@ -456,10 +456,6 @@ public class AvgIT extends AbstractNumericTestCase { } }; } - - @Override - public void scriptRemoved(CompiledScript script) { - } } /** @@ -564,10 +560,6 @@ public class AvgIT extends AbstractNumericTestCase { }; } - @Override - public void scriptRemoved(CompiledScript script) { - } - @Override public boolean isInlineScriptEnabled() { return true; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/SumIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/SumIT.java index a142f43bd5a..186bc8fb27b 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/SumIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/SumIT.java @@ -453,10 +453,6 @@ public class SumIT extends AbstractNumericTestCase { }; } - @Override - public void scriptRemoved(CompiledScript script) { - } - @Override public boolean isInlineScriptEnabled() { return true; @@ -573,10 +569,6 @@ public class SumIT extends AbstractNumericTestCase { }; } - @Override - public void scriptRemoved(CompiledScript script) { - } - @Override public boolean isInlineScriptEnabled() { return true; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/ValueCountIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/ValueCountIT.java index d79edcc41b6..7de37fdb6a8 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/ValueCountIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/ValueCountIT.java @@ -318,10 +318,6 @@ public class ValueCountIT extends ESIntegTestCase { }; } - @Override - public void scriptRemoved(CompiledScript script) { - } - @Override public boolean isInlineScriptEnabled() { return true; diff --git a/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java b/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java index 3fe1d2a0480..5822372bfa9 100644 --- a/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java @@ -46,7 +46,6 @@ import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.env.Environment; -import org.elasticsearch.env.EnvironmentModule; import org.elasticsearch.index.Index; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryParseContext; @@ -132,7 +131,10 @@ public class SearchSourceBuilderTests extends ESTestCase { scriptSettings.add(InternalSettingsPlugin.VERSION_CREATED); SettingsModule settingsModule = new SettingsModule(settings, scriptSettings, Collections.emptyList()); injector = new ModulesBuilder().add( - new EnvironmentModule(new Environment(settings), threadPool), settingsModule, + (b) -> { + b.bind(Environment.class).toInstance(new Environment(settings)); + b.bind(ThreadPool.class).toInstance(threadPool); + }, settingsModule, scriptModule, new IndicesModule(namedWriteableRegistry) { @Override protected void configure() { diff --git a/core/src/test/java/org/elasticsearch/transport/NettySizeHeaderFrameDecoderTests.java b/core/src/test/java/org/elasticsearch/transport/NettySizeHeaderFrameDecoderTests.java index 95ec6dad9bd..f436b719260 100644 --- a/core/src/test/java/org/elasticsearch/transport/NettySizeHeaderFrameDecoderTests.java +++ b/core/src/test/java/org/elasticsearch/transport/NettySizeHeaderFrameDecoderTests.java @@ -66,7 +66,7 @@ public class NettySizeHeaderFrameDecoderTests extends ESTestCase { threadPool = new ThreadPool(settings); NetworkService networkService = new NetworkService(settings); BigArrays bigArrays = new MockBigArrays(Settings.EMPTY, new NoneCircuitBreakerService()); - nettyTransport = new NettyTransport(settings, threadPool, networkService, bigArrays, Version.CURRENT, new NamedWriteableRegistry(), + nettyTransport = new NettyTransport(settings, threadPool, networkService, bigArrays, new NamedWriteableRegistry(), new NoneCircuitBreakerService()); nettyTransport.start(); TransportService transportService = new TransportService(settings, nettyTransport, threadPool); diff --git a/core/src/test/java/org/elasticsearch/transport/NettyTransportServiceHandshakeTests.java b/core/src/test/java/org/elasticsearch/transport/NettyTransportServiceHandshakeTests.java index 2213d7eb4cf..7bbd6e0fea7 100644 --- a/core/src/test/java/org/elasticsearch/transport/NettyTransportServiceHandshakeTests.java +++ b/core/src/test/java/org/elasticsearch/transport/NettyTransportServiceHandshakeTests.java @@ -64,7 +64,6 @@ public class NettyTransportServiceHandshakeTests extends ESTestCase { threadPool, new NetworkService(settings), BigArrays.NON_RECYCLING_INSTANCE, - Version.CURRENT, new NamedWriteableRegistry(), new NoneCircuitBreakerService()); TransportService transportService = new MockTransportService(settings, transport, threadPool); diff --git a/core/src/test/java/org/elasticsearch/transport/TransportModuleTests.java b/core/src/test/java/org/elasticsearch/transport/TransportModuleTests.java index 20413888281..e5c734cbfb6 100644 --- a/core/src/test/java/org/elasticsearch/transport/TransportModuleTests.java +++ b/core/src/test/java/org/elasticsearch/transport/TransportModuleTests.java @@ -36,9 +36,9 @@ public class TransportModuleTests extends ModuleTestCase { static class FakeTransport extends AssertingLocalTransport { @Inject - public FakeTransport(Settings settings, CircuitBreakerService circuitBreakerService, ThreadPool threadPool, Version version, + public FakeTransport(Settings settings, CircuitBreakerService circuitBreakerService, ThreadPool threadPool, NamedWriteableRegistry namedWriteableRegistry) { - super(settings, circuitBreakerService, threadPool, version, namedWriteableRegistry); + super(settings, circuitBreakerService, threadPool, namedWriteableRegistry); } } diff --git a/core/src/test/java/org/elasticsearch/transport/netty/NettyScheduledPingTests.java b/core/src/test/java/org/elasticsearch/transport/netty/NettyScheduledPingTests.java index a98a038f6fd..df7dcb0714b 100644 --- a/core/src/test/java/org/elasticsearch/transport/netty/NettyScheduledPingTests.java +++ b/core/src/test/java/org/elasticsearch/transport/netty/NettyScheduledPingTests.java @@ -65,14 +65,14 @@ public class NettyScheduledPingTests extends ESTestCase { NamedWriteableRegistry registryA = new NamedWriteableRegistry(); final NettyTransport nettyA = new NettyTransport(settings, threadPool, new NetworkService(settings), - BigArrays.NON_RECYCLING_INSTANCE, Version.CURRENT, registryA, circuitBreakerService); + BigArrays.NON_RECYCLING_INSTANCE, registryA, circuitBreakerService); MockTransportService serviceA = new MockTransportService(settings, nettyA, threadPool); serviceA.start(); serviceA.acceptIncomingRequests(); NamedWriteableRegistry registryB = new NamedWriteableRegistry(); final NettyTransport nettyB = new NettyTransport(settings, threadPool, new NetworkService(settings), - BigArrays.NON_RECYCLING_INSTANCE, Version.CURRENT, registryB, circuitBreakerService); + BigArrays.NON_RECYCLING_INSTANCE, registryB, circuitBreakerService); MockTransportService serviceB = new MockTransportService(settings, nettyB, threadPool); serviceB.start(); diff --git a/core/src/test/java/org/elasticsearch/transport/netty/NettyTransportIT.java b/core/src/test/java/org/elasticsearch/transport/netty/NettyTransportIT.java index f70c7b27492..2f89435c6df 100644 --- a/core/src/test/java/org/elasticsearch/transport/netty/NettyTransportIT.java +++ b/core/src/test/java/org/elasticsearch/transport/netty/NettyTransportIT.java @@ -93,9 +93,9 @@ public class NettyTransportIT extends ESIntegTestCase { @Inject public ExceptionThrowingNettyTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, - Version version, NamedWriteableRegistry namedWriteableRegistry, + NamedWriteableRegistry namedWriteableRegistry, CircuitBreakerService circuitBreakerService) { - super(settings, threadPool, networkService, bigArrays, version, namedWriteableRegistry, circuitBreakerService); + super(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService); } @Override diff --git a/core/src/test/java/org/elasticsearch/transport/netty/NettyTransportMultiPortTests.java b/core/src/test/java/org/elasticsearch/transport/netty/NettyTransportMultiPortTests.java index 0ed0cf3ec97..6fdc214d18d 100644 --- a/core/src/test/java/org/elasticsearch/transport/netty/NettyTransportMultiPortTests.java +++ b/core/src/test/java/org/elasticsearch/transport/netty/NettyTransportMultiPortTests.java @@ -136,7 +136,7 @@ public class NettyTransportMultiPortTests extends ESTestCase { private NettyTransport startNettyTransport(Settings settings, ThreadPool threadPool) { BigArrays bigArrays = new MockBigArrays(Settings.EMPTY, new NoneCircuitBreakerService()); - NettyTransport nettyTransport = new NettyTransport(settings, threadPool, new NetworkService(settings), bigArrays, Version.CURRENT, + NettyTransport nettyTransport = new NettyTransport(settings, threadPool, new NetworkService(settings), bigArrays, new NamedWriteableRegistry(), new NoneCircuitBreakerService()); nettyTransport.start(); diff --git a/core/src/test/java/org/elasticsearch/transport/netty/SimpleNettyTransportTests.java b/core/src/test/java/org/elasticsearch/transport/netty/SimpleNettyTransportTests.java index f3cfcc3bebe..96275d099db 100644 --- a/core/src/test/java/org/elasticsearch/transport/netty/SimpleNettyTransportTests.java +++ b/core/src/test/java/org/elasticsearch/transport/netty/SimpleNettyTransportTests.java @@ -42,7 +42,7 @@ public class SimpleNettyTransportTests extends AbstractSimpleTransportTestCase { @Override protected MockTransportService build(Settings settings, Version version) { settings = Settings.builder().put(settings).put(TransportSettings.PORT.getKey(), "0").build(); - MockTransportService transportService = MockTransportService.nettyFromThreadPool(settings, version, threadPool); + MockTransportService transportService = MockTransportService.nettyFromThreadPool(settings, threadPool, version); transportService.start(); return transportService; } diff --git a/core/src/test/java/org/elasticsearch/update/UpdateIT.java b/core/src/test/java/org/elasticsearch/update/UpdateIT.java index 0ae1b4e435a..4121543a7a0 100644 --- a/core/src/test/java/org/elasticsearch/update/UpdateIT.java +++ b/core/src/test/java/org/elasticsearch/update/UpdateIT.java @@ -144,10 +144,6 @@ public class UpdateIT extends ESIntegTestCase { throw new UnsupportedOperationException(); } - @Override - public void scriptRemoved(CompiledScript script) { - } - @Override public boolean isInlineScriptEnabled() { return true; @@ -214,15 +210,10 @@ public class UpdateIT extends ESIntegTestCase { throw new UnsupportedOperationException(); } - @Override - public void scriptRemoved(CompiledScript script) { - } - @Override public boolean isInlineScriptEnabled() { return true; } - } public static class ScriptedUpsertScriptPlugin extends Plugin implements ScriptPlugin { @@ -285,10 +276,6 @@ public class UpdateIT extends ESIntegTestCase { throw new UnsupportedOperationException(); } - @Override - public void scriptRemoved(CompiledScript script) { - } - @Override public boolean isInlineScriptEnabled() { return true; @@ -357,10 +344,6 @@ public class UpdateIT extends ESIntegTestCase { throw new UnsupportedOperationException(); } - @Override - public void scriptRemoved(CompiledScript script) { - } - @Override public boolean isInlineScriptEnabled() { return true; diff --git a/docs/reference/index-modules/store.asciidoc b/docs/reference/index-modules/store.asciidoc index 54080e365c2..ee7fd8766fd 100644 --- a/docs/reference/index-modules/store.asciidoc +++ b/docs/reference/index-modules/store.asciidoc @@ -7,9 +7,9 @@ The store module allows you to control how index data is stored and accessed on [[file-system]] === File system storage types -There are different file system implementations or _storage types_. The best -one for the operating environment will be automatically chosen: `simplefs` on -Windows 32bit, `niofs` on other 32bit systems and `mmapfs` on 64bit systems. +There are different file system implementations or _storage types_. By default, +elasticsearch will pick the best implementation based on the operating +environment. This can be overridden for all indices by adding this to the `config/elasticsearch.yml` file: @@ -36,6 +36,12 @@ experimental[This is an expert-only setting and may be removed in the future] The following sections lists all the different storage types supported. +`fs`:: + +Default file system implementation. This will pick the best implementation +depending on the operating environment: `simplefs` on Windows 32bit, `niofs` +on other 32bit systems and `mmapfs` on 64bit systems. + [[simplefs]]`simplefs`:: The Simple FS type is a straightforward implementation of file system @@ -60,13 +66,64 @@ process equal to the size of the file being mapped. Before using this class, be sure you have allowed plenty of <>. -[[default_fs]]`default_fs` deprecated[5.0.0, The `default_fs` store type is deprecated - use `mmapfs` instead]:: +[[default_fs]]`default_fs` deprecated[5.0.0, The `default_fs` store type is deprecated - use `fs` instead]:: -The `default` type is a hybrid of NIO FS and MMapFS, which chooses the best -file system for each type of file. Currently only the Lucene term dictionary, -doc values and points files are memory mapped to reduce the impact on the -operating system. All other files are opened using Lucene `NIOFSDirectory`. -Address space settings (<>) might also apply if your term -dictionary are large, if you index many fields that use points (numerics, dates -and ip addresses) or if you have many fields with doc values. +The `default` type is deprecated and is aliased to `fs` for backward +compatibility. +=== Pre-loading data into the file system cache + +experimental[This is an expert-only setting and may be removed in the future] + +By default, elasticsearch completely relies on the operating system file system +cache for caching I/O operations. It is possible to set `index.store.preload` +in order to tell the operating system to load the content of hot index +files into memory upon opening. This setting accept a comma-separated list of +files extensions: all files whose extenion is in the list will be pre-loaded +upon opening. This can be useful to improve search performance of an index, +especially when the host operating system is restarted, since this causes the +file system cache to be trashed. However note that this may slow down the +opening of indices, as they will only become available after data have been +loaded into physical memory. + +This setting is best-effort only and may not work at all depending on the store +type and host operating system. + +The `index.store.pre_load` is a static setting that can either be set in the +`config/elasticsearch.yml`: + +[source,yaml] +--------------------------------- +index.store.pre_load: ["nvd", "dvd"] +--------------------------------- + +or in the index settings at index creation time: + +[source,js] +--------------------------------- +PUT /my_index +{ + "settings": { + "index.store.pre_load": ["nvd", "dvd"] + } +} +--------------------------------- + +The default value is the empty array, which means that nothing will be loaded +into the file-system cache eagerly. For indices that are actively searched, +you might want to set it to `["nvd", "dvd"]`, which will cause norms and doc +values to be loaded eagerly into physical memory. These are the two first +extensions to look at since elasticsearch performs random access on them. + +A wildcard can be used in order to indicate that all files should be preloaded: +`index.store.pre_load: ["*"]`. Note however that it is generally not useful to +load all files into memory, in particular those for stored fields and term +vectors, so a better option might be to set it to +`["nvd", "dvd", "tim", "doc", "dim"]`, which will preload norms, doc values, +terms dictionaries, postings lists and points, which are the most important +parts of the index for search and aggregations. + +Note that this setting can be dangerous on indices that are larger than the size +of the main memory of the host, as it would cause the filesystem cache to be +trashed upon reopens after large merges, which would make indexing and searching +_slower_. diff --git a/docs/reference/modules/scripting/painless.asciidoc b/docs/reference/modules/scripting/painless.asciidoc index 20b301bda31..2c753e09039 100644 --- a/docs/reference/modules/scripting/painless.asciidoc +++ b/docs/reference/modules/scripting/painless.asciidoc @@ -133,7 +133,7 @@ GET hockey/_search "order": "asc", "script": { "lang": "painless", - "inline": "doc['first'].value + ' ' + doc['last'].value" + "inline": "doc['first.keyword'].value + ' ' + doc['last.keyword'].value" } } } diff --git a/docs/reference/modules/snapshots.asciidoc b/docs/reference/modules/snapshots.asciidoc index d000805e5e9..5931dbc588f 100644 --- a/docs/reference/modules/snapshots.asciidoc +++ b/docs/reference/modules/snapshots.asciidoc @@ -8,7 +8,7 @@ backends are available via officially supported repository plugins. [float] === Repositories -Before any snapshot or restore operation can be performed a snapshot repository should be registered in +Before any snapshot or restore operation can be performed, a snapshot repository should be registered in Elasticsearch. The repository settings are repository-type specific. See below for details. [source,js] diff --git a/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngineService.java b/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngineService.java index fdede1e77bc..72a5169593a 100644 --- a/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngineService.java +++ b/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngineService.java @@ -266,11 +266,6 @@ public class ExpressionScriptEngineService extends AbstractComponent implements @Override public void close() {} - @Override - public void scriptRemoved(CompiledScript script) { - // Nothing to do - } - @Override public boolean isInlineScriptEnabled() { return true; diff --git a/modules/lang-groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java b/modules/lang-groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java index 017e51280c0..105d42c8c86 100644 --- a/modules/lang-groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java +++ b/modules/lang-groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java @@ -33,9 +33,11 @@ import org.codehaus.groovy.classgen.GeneratorContext; import org.codehaus.groovy.control.CompilationFailedException; import org.codehaus.groovy.control.CompilePhase; import org.codehaus.groovy.control.CompilerConfiguration; +import org.codehaus.groovy.control.MultipleCompilationErrorsException; import org.codehaus.groovy.control.SourceUnit; import org.codehaus.groovy.control.customizers.CompilationCustomizer; import org.codehaus.groovy.control.customizers.ImportCustomizer; +import org.codehaus.groovy.control.messages.Message; import org.elasticsearch.SpecialPermission; import org.elasticsearch.bootstrap.BootstrapInfo; import org.elasticsearch.common.Nullable; @@ -49,20 +51,26 @@ import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.LeafSearchScript; import org.elasticsearch.script.ScoreAccessor; import org.elasticsearch.script.ScriptEngineService; -import org.elasticsearch.script.GeneralScriptException; +import org.elasticsearch.script.ScriptException; import org.elasticsearch.script.SearchScript; import org.elasticsearch.search.lookup.LeafSearchLookup; import org.elasticsearch.search.lookup.SearchLookup; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import static java.util.Collections.emptyList; + /** * Provides the infrastructure for Groovy as a scripting language for Elasticsearch */ @@ -78,81 +86,40 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri */ public static final String GROOVY_INDY_SETTING_NAME = "indy"; - private final GroovyClassLoader loader; + /** + * Classloader used as a parent classloader for all Groovy scripts + */ + private final ClassLoader loader; public GroovyScriptEngineService(Settings settings) { super(settings); - - ImportCustomizer imports = new ImportCustomizer(); - imports.addStarImports("org.joda.time"); - imports.addStaticStars("java.lang.Math"); - - CompilerConfiguration config = new CompilerConfiguration(); - - config.addCompilationCustomizers(imports); - // Add BigDecimal -> Double transformer - config.addCompilationCustomizers(new GroovyBigDecimalTransformer(CompilePhase.CONVERSION)); - - // always enable invokeDynamic, not the crazy softreference-based stuff - config.getOptimizationOptions().put(GROOVY_INDY_SETTING_NAME, true); - - // Groovy class loader to isolate Groovy-land code - // classloader created here + // Creates the classloader here in order to isolate Groovy-land code final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new SpecialPermission()); } - this.loader = AccessController.doPrivileged(new PrivilegedAction() { - @Override - public GroovyClassLoader run() { - // snapshot our context (which has permissions for classes), since the script has none - final AccessControlContext engineContext = AccessController.getContext(); - return new GroovyClassLoader(new ClassLoader(getClass().getClassLoader()) { - @Override - protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - if (sm != null) { - try { - engineContext.checkPermission(new ClassPermission(name)); - } catch (SecurityException e) { - throw new ClassNotFoundException(name, e); - } + this.loader = AccessController.doPrivileged((PrivilegedAction) () -> { + // snapshot our context (which has permissions for classes), since the script has none + AccessControlContext context = AccessController.getContext(); + return new ClassLoader(getClass().getClassLoader()) { + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (sm != null) { + try { + context.checkPermission(new ClassPermission(name)); + } catch (SecurityException e) { + throw new ClassNotFoundException(name, e); } - return super.loadClass(name, resolve); } - }, config); - } - }); - } - - @Override - public void close() { - loader.clearCache(); - // close classloader here (why do we do this?) - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new SpecialPermission()); - } - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Void run() { - try { - loader.close(); - } catch (IOException e) { - logger.warn("Unable to close Groovy loader", e); + return super.loadClass(name, resolve); } - return null; - } + }; }); } @Override - public void scriptRemoved(@Nullable CompiledScript script) { - // script could be null, meaning the script has already been garbage collected - if (script == null || NAME.equals(script.lang())) { - // Clear the cache, this removes old script versions from the - // cache to prevent running out of PermGen space - loader.clearCache(); - } + public void close() throws IOException { + // Nothing to do here } @Override @@ -167,30 +134,34 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri @Override public Object compile(String scriptName, String scriptSource, Map params) { - try { - // we reuse classloader, so do a security check just in case. - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new SpecialPermission()); - } - String fake = MessageDigests.toHexString(MessageDigests.sha1().digest(scriptSource.getBytes(StandardCharsets.UTF_8))); - // same logic as GroovyClassLoader.parseClass() but with a different codesource string: - return AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Class run() { - GroovyCodeSource gcs = new GroovyCodeSource(scriptSource, fake, BootstrapInfo.UNTRUSTED_CODEBASE); - gcs.setCachable(false); - // TODO: we could be more complicated and paranoid, and move this to separate block, to - // sandbox the compilation process itself better. - return loader.parseClass(gcs); - } - }); - } catch (Throwable e) { - if (logger.isTraceEnabled()) { - logger.trace("exception compiling Groovy script:", e); - } - throw new GeneralScriptException("failed to compile groovy script", e); + // Create the script class name + String className = MessageDigests.toHexString(MessageDigests.sha1().digest(scriptSource.getBytes(StandardCharsets.UTF_8))); + + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new SpecialPermission()); } + return AccessController.doPrivileged((PrivilegedAction) () -> { + try { + GroovyCodeSource codeSource = new GroovyCodeSource(scriptSource, className, BootstrapInfo.UNTRUSTED_CODEBASE); + codeSource.setCachable(false); + + CompilerConfiguration configuration = new CompilerConfiguration() + .addCompilationCustomizers(new ImportCustomizer().addStarImports("org.joda.time").addStaticStars("java.lang.Math")) + .addCompilationCustomizers(new GroovyBigDecimalTransformer(CompilePhase.CONVERSION)); + + // always enable invokeDynamic, not the crazy softreference-based stuff + configuration.getOptimizationOptions().put(GROOVY_INDY_SETTING_NAME, true); + + GroovyClassLoader groovyClassLoader = new GroovyClassLoader(loader, configuration); + return groovyClassLoader.parseClass(codeSource); + } catch (Throwable e) { + if (logger.isTraceEnabled()) { + logger.trace("Exception compiling Groovy script:", e); + } + throw convertToScriptException("Error compiling script " + className, scriptSource, e); + } + }); } /** @@ -215,7 +186,7 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri } return new GroovyScript(compiledScript, createScript(compiledScript.compiled(), allVars), this.logger); } catch (ReflectiveOperationException e) { - throw new GeneralScriptException("failed to build executable " + compiledScript, e); + throw convertToScriptException("Failed to build executable script", compiledScript.name(), e); } } @@ -235,7 +206,7 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri try { scriptObject = createScript(compiledScript.compiled(), allVars); } catch (ReflectiveOperationException e) { - throw new GeneralScriptException("failed to build search " + compiledScript, e); + throw convertToScriptException("Failed to build search script", compiledScript.name(), e); } return new GroovyScript(compiledScript, scriptObject, leafLookup, logger); } @@ -248,6 +219,29 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri }; } + /** + * Converts a {@link Throwable} to a {@link ScriptException} + */ + private ScriptException convertToScriptException(String message, String source, Throwable cause) { + List stack = new ArrayList<>(); + if (cause instanceof MultipleCompilationErrorsException) { + @SuppressWarnings({"unchecked"}) + List errors = (List) ((MultipleCompilationErrorsException) cause).getErrorCollector().getErrors(); + for (Message error : errors) { + try (StringWriter writer = new StringWriter()) { + error.write(new PrintWriter(writer)); + stack.add(writer.toString()); + } catch (IOException e1) { + logger.error("failed to write compilation error message to the stack", e1); + } + } + } else if (cause instanceof CompilationFailedException) { + CompilationFailedException error = (CompilationFailedException) cause; + stack.add(error.getMessage()); + } + throw new ScriptException(message, cause, stack, source, NAME); + } + public static final class GroovyScript implements ExecutableScript, LeafSearchScript { private final CompiledScript compiledScript; @@ -298,17 +292,12 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri try { // NOTE: we truncate the stack because IndyInterface has security issue (needs getClassLoader) // we don't do a security check just as a tradeoff, it cannot really escalate to anything. - return AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Object run() { - return script.run(); - } - }); + return AccessController.doPrivileged((PrivilegedAction) script::run); } catch (Throwable e) { if (logger.isTraceEnabled()) { logger.trace("failed to run {}", e, compiledScript); } - throw new GeneralScriptException("failed to run " + compiledScript, e); + throw new ScriptException("Error evaluating " + compiledScript.name(), e, emptyList(), "", compiledScript.lang()); } } diff --git a/modules/lang-groovy/src/main/plugin-metadata/plugin-security.policy b/modules/lang-groovy/src/main/plugin-metadata/plugin-security.policy index 82482448677..13d00d6d17c 100644 --- a/modules/lang-groovy/src/main/plugin-metadata/plugin-security.policy +++ b/modules/lang-groovy/src/main/plugin-metadata/plugin-security.policy @@ -26,8 +26,6 @@ grant { permission java.lang.RuntimePermission "accessDeclaredMembers"; permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.reflect"; - // needed by GroovyScriptEngineService to close its classloader (why?) - permission java.lang.RuntimePermission "closeClassLoader"; // Allow executing groovy scripts with codesource of /untrusted permission groovy.security.GroovyCodeSourcePermission "/untrusted"; diff --git a/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovySecurityTests.java b/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovySecurityTests.java index 51aad9b2fba..96a5343913d 100644 --- a/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovySecurityTests.java +++ b/modules/lang-groovy/src/test/java/org/elasticsearch/script/groovy/GroovySecurityTests.java @@ -24,7 +24,7 @@ import org.apache.lucene.util.Constants; import org.codehaus.groovy.control.MultipleCompilationErrorsException; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.script.CompiledScript; -import org.elasticsearch.script.GeneralScriptException; +import org.elasticsearch.script.ScriptException; import org.elasticsearch.script.ScriptService; import org.elasticsearch.test.ESTestCase; @@ -151,7 +151,7 @@ public class GroovySecurityTests extends ESTestCase { try { doTest(script); fail("did not get expected exception"); - } catch (GeneralScriptException expected) { + } catch (ScriptException expected) { Throwable cause = expected.getCause(); assertNotNull(cause); if (exceptionClass.isAssignableFrom(cause.getClass()) == false) { diff --git a/modules/lang-groovy/src/test/resources/rest-api-spec/test/lang_groovy/16_update2.yaml b/modules/lang-groovy/src/test/resources/rest-api-spec/test/lang_groovy/16_update2.yaml index 5e1f99eeeff..5849874c02e 100644 --- a/modules/lang-groovy/src/test/resources/rest-api-spec/test/lang_groovy/16_update2.yaml +++ b/modules/lang-groovy/src/test/resources/rest-api-spec/test/lang_groovy/16_update2.yaml @@ -51,7 +51,7 @@ - do: - catch: /Unable.to.parse.*/ + catch: /script_exception,.+Error.compiling.script.*/ put_script: id: "1" lang: "groovy" diff --git a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/MustacheScriptEngineService.java b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/MustacheScriptEngineService.java index 283a72b02af..2a48567333b 100644 --- a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/MustacheScriptEngineService.java +++ b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/MustacheScriptEngineService.java @@ -133,11 +133,6 @@ public final class MustacheScriptEngineService extends AbstractComponent impleme // Nothing to do here } - @Override - public void scriptRemoved(CompiledScript script) { - // Nothing to do here - } - // permission checked before doing crazy reflection static final SpecialPermission SPECIAL_PERMISSION = new SpecialPermission(); diff --git a/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java b/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java index f0422314c74..60316818a79 100644 --- a/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java +++ b/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java @@ -38,7 +38,6 @@ import org.elasticsearch.common.settings.SettingsModule; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.env.Environment; -import org.elasticsearch.env.EnvironmentModule; import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.analysis.AnalysisRegistry; @@ -59,7 +58,6 @@ import org.elasticsearch.indices.breaker.NoneCircuitBreakerService; import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache; import org.elasticsearch.indices.mapper.MapperRegistry; import org.elasticsearch.indices.query.IndicesQueriesRegistry; -import org.elasticsearch.script.ScriptEngineRegistry; import org.elasticsearch.script.ScriptModule; import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.mustache.MustacheScriptEngineService; @@ -110,7 +108,10 @@ public class TemplateQueryParserTests extends ESTestCase { SettingsModule settingsModule = new SettingsModule(settings, scriptSettings, Collections.emptyList()); final ThreadPool threadPool = new ThreadPool(settings); injector = new ModulesBuilder().add( - new EnvironmentModule(new Environment(settings), threadPool), + (b) -> { + b.bind(Environment.class).toInstance(new Environment(settings)); + b.bind(ThreadPool.class).toInstance(threadPool); + }, settingsModule, new SearchModule(settings, new NamedWriteableRegistry()) { @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java index 7c7ff5f7f5a..5461771bca6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java @@ -28,6 +28,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; +import java.util.BitSet; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -222,19 +223,25 @@ public final class Def { */ static MethodHandle lookupMethod(Lookup lookup, MethodType callSiteType, Class receiverClass, String name, Object args[]) throws Throwable { - long recipe = (Long) args[0]; + String recipeString = (String) args[0]; int numArguments = callSiteType.parameterCount(); // simple case: no lambdas - if (recipe == 0) { + if (recipeString.isEmpty()) { return lookupMethodInternal(receiverClass, name, numArguments - 1).handle; } + // convert recipe string to a bitset for convenience (the code below should be refactored...) + BitSet lambdaArgs = new BitSet(); + for (int i = 0; i < recipeString.length(); i++) { + lambdaArgs.set(recipeString.charAt(i)); + } + // otherwise: first we have to compute the "real" arity. This is because we have extra arguments: // e.g. f(a, g(x), b, h(y), i()) looks like f(a, g, x, b, h, y, i). int arity = callSiteType.parameterCount() - 1; int upTo = 1; - for (int i = 0; i < numArguments; i++) { - if ((recipe & (1L << (i - 1))) != 0) { + for (int i = 1; i < numArguments; i++) { + if (lambdaArgs.get(i - 1)) { String signature = (String) args[upTo++]; int numCaptures = Integer.parseInt(signature.substring(signature.indexOf(',')+1)); arity -= numCaptures; @@ -250,7 +257,7 @@ public final class Def { upTo = 1; for (int i = 1; i < numArguments; i++) { // its a functional reference, replace the argument with an impl - if ((recipe & (1L << (i - 1))) != 0) { + if (lambdaArgs.get(i - 1)) { // decode signature of form 'type.call,2' String signature = (String) args[upTo++]; int separator = signature.indexOf('.'); @@ -335,6 +342,12 @@ public final class Def { MethodHandle.class); handle = (MethodHandle) accessor.invokeExact(); } catch (NoSuchFieldException | IllegalAccessException e) { + // is it a synthetic method? If we generated the method ourselves, be more helpful. It can only fail + // because the arity does not match the expected interface type. + if (call.contains("$")) { + throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.name + + "] in [" + clazz.clazz + "]"); + } throw new IllegalArgumentException("Unknown call [" + call + "] with [" + arity + "] arguments."); } ref = new FunctionRef(clazz, interfaceMethod, handle, captures); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java index fa533eff213..9640629cb87 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java @@ -431,11 +431,11 @@ public final class DefBootstrap { if (args.length == 0) { throw new BootstrapMethodError("Invalid number of parameters for method call"); } - if (args[0] instanceof Long == false) { + if (args[0] instanceof String == false) { throw new BootstrapMethodError("Illegal parameter for method call: " + args[0]); } - long recipe = (Long) args[0]; - int numLambdas = Long.bitCount(recipe); + String recipe = (String) args[0]; + int numLambdas = recipe.length(); if (numLambdas > type.parameterCount()) { throw new BootstrapMethodError("Illegal recipe for method call: too many bits"); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java index 6a39d99f4e3..72676f1c04c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java @@ -176,7 +176,12 @@ public class FunctionRef { * If the interface expects a primitive type to be returned, we can't return Object, * But we can set SAM to the wrapper version, and a cast will take place */ - private static MethodType adapt(MethodType expected, MethodType actual) { + private MethodType adapt(MethodType expected, MethodType actual) { + // add some checks, now that we've set everything up, to deliver exceptions as early as possible. + if (expected.parameterCount() != actual.parameterCount()) { + throw new IllegalArgumentException("Incorrect number of parameters for [" + invokedName + + "] in [" + invokedType.returnType() + "]"); + } if (expected.returnType().isPrimitive() && actual.returnType() == Object.class) { actual = actual.changeReturnType(MethodType.methodType(expected.returnType()).wrap().returnType()); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/LambdaLocals.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/LambdaLocals.java deleted file mode 100644 index 9c01bc4c628..00000000000 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/LambdaLocals.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.painless; - -import org.elasticsearch.painless.Definition.Type; - -import java.util.List; -import java.util.Objects; - -/** Extension of locals for lambdas */ -// Note: this isn't functional yet, it throws UOE -// TODO: implement slot renumbering for captures. -class LambdaLocals extends Locals { - private List captures; - - LambdaLocals(Locals parent, List parameters, List captures) { - super(parent); - for (Parameter parameter : parameters) { - defineVariable(parameter.location, parameter.type, parameter.name, false); - } - this.captures = Objects.requireNonNull(captures); - } - - @Override - public Variable getVariable(Location location, String name) { - Variable variable = lookupVariable(location, name); - if (variable != null) { - return variable; - } - if (getParent() != null) { - variable = getParent().getVariable(location, name); - if (variable != null) { - assert captures != null; // unused right now - // make it read-only, and record that it was used. - throw new UnsupportedOperationException("lambda capture is not supported"); - } - } - throw location.createError(new IllegalArgumentException("Variable [" + name + "] is not defined.")); - } - - @Override - public Type getReturnType() { - return Definition.DEF_TYPE; - } -} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java index 8cb99ed2404..7ffa0a169b7 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java @@ -35,7 +35,7 @@ import java.util.Set; /** * Tracks user defined methods and variables across compilation phases. */ -public class Locals { +public final class Locals { /** Reserved word: params map parameter */ public static final String PARAMS = "params"; @@ -64,16 +64,30 @@ public class Locals { return new Locals(currentScope); } - /** Creates a new lambda scope inside the current scope */ - public static Locals newLambdaScope(Locals currentScope, List parameters, List captures) { - return new LambdaLocals(currentScope, parameters, captures); + /** + * Creates a new lambda scope inside the current scope + *

+ * This is just like {@link #newFunctionScope}, except the captured parameters are made read-only. + */ + public static Locals newLambdaScope(Locals programScope, List parameters, int captureCount, int maxLoopCounter) { + Locals locals = new Locals(programScope, Definition.DEF_TYPE); + for (int i = 0; i < parameters.size(); i++) { + Parameter parameter = parameters.get(i); + boolean isCapture = i < captureCount; + locals.addVariable(parameter.location, parameter.type, parameter.name, isCapture); + } + // Loop counter to catch infinite loops. Internal use only. + if (maxLoopCounter > 0) { + locals.defineVariable(null, Definition.INT_TYPE, LOOP, true); + } + return locals; } /** Creates a new function scope inside the current scope */ public static Locals newFunctionScope(Locals programScope, Type returnType, List parameters, int maxLoopCounter) { Locals locals = new Locals(programScope, returnType); for (Parameter parameter : parameters) { - locals.defineVariable(parameter.location, parameter.type, parameter.name, false); + locals.addVariable(parameter.location, parameter.type, parameter.name, false); } // Loop counter to catch infinite loops. Internal use only. if (maxLoopCounter > 0) { @@ -129,7 +143,7 @@ public class Locals { } /** Checks if a variable exists or not, in this scope or any parents. */ - public final boolean hasVariable(String name) { + public boolean hasVariable(String name) { Variable variable = lookupVariable(null, name); if (variable != null) { return true; @@ -153,7 +167,7 @@ public class Locals { } /** Looks up a method. Returns null if the method does not exist. */ - public final Method getMethod(MethodKey key) { + public Method getMethod(MethodKey key) { Method method = lookupMethod(key); if (method != null) { return method; @@ -165,7 +179,7 @@ public class Locals { } /** Creates a new variable. Throws IAE if the variable has already been defined (even in a parent) or reserved. */ - public final Variable addVariable(Location location, Type type, String name, boolean readonly) { + public Variable addVariable(Location location, Type type, String name, boolean readonly) { if (hasVariable(name)) { throw location.createError(new IllegalArgumentException("Variable [" + name + "] is already defined.")); } @@ -196,23 +210,23 @@ public class Locals { // return type of this scope private final Type returnType; // next slot number to assign - int nextSlotNumber; + private int nextSlotNumber; // variable name -> variable - Map variables; + private Map variables; // method name+arity -> methods - Map methods; + private Map methods; /** * Create a new Locals */ - Locals(Locals parent) { + private Locals(Locals parent) { this(parent, parent.getReturnType()); } /** * Create a new Locals with specified return type */ - Locals(Locals parent, Type returnType) { + private Locals(Locals parent, Type returnType) { this.parent = parent; this.returnType = returnType; if (parent == null) { @@ -223,12 +237,12 @@ public class Locals { } /** Returns the parent scope */ - Locals getParent() { + private Locals getParent() { return parent; } /** Looks up a variable at this scope only. Returns null if the variable does not exist. */ - Variable lookupVariable(Location location, String name) { + private Variable lookupVariable(Location location, String name) { if (variables == null) { return null; } @@ -236,7 +250,7 @@ public class Locals { } /** Looks up a method at this scope only. Returns null if the method does not exist. */ - Method lookupMethod(MethodKey key) { + private Method lookupMethod(MethodKey key) { if (methods == null) { return null; } @@ -245,19 +259,17 @@ public class Locals { /** Defines a variable at this scope internally. */ - Variable defineVariable(Location location, Type type, String name, boolean readonly) { + private Variable defineVariable(Location location, Type type, String name, boolean readonly) { if (variables == null) { variables = new HashMap<>(); } - Variable variable = new Variable(location, name, type, readonly); - variable.slot = getNextSlot(); + Variable variable = new Variable(location, name, type, getNextSlot(), readonly); variables.put(name, variable); // TODO: check result nextSlotNumber += type.type.getSize(); return variable; } - // TODO: make private, thats bogus - public void addMethod(Method method) { + private void addMethod(Method method) { if (methods == null) { methods = new HashMap<>(); } @@ -266,7 +278,7 @@ public class Locals { } - int getNextSlot() { + private int getNextSlot() { return nextSlotNumber; } @@ -274,13 +286,14 @@ public class Locals { public final Location location; public final String name; public final Type type; - int slot = -1; public final boolean readonly; + private final int slot; - public Variable(Location location, String name, Type type, boolean readonly) { + public Variable(Location location, String name, Type type, int slot, boolean readonly) { this.location = location; this.name = name; this.type = type; + this.slot = slot; this.readonly = readonly; } @@ -289,7 +302,7 @@ public class Locals { } } - public static class Parameter { + public static final class Parameter { public final Location location; public final String name; public final Type type; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java index 365060fe004..31c4e22dd0c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java @@ -208,15 +208,6 @@ public final class PainlessScriptEngineService extends AbstractComponent impleme }; } - /** - * Action taken when a script is removed from the cache. - * @param script The removed script. - */ - @Override - public void scriptRemoved(final CompiledScript script) { - // Nothing to do. - } - /** * Action taken when the engine is closed. */ diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java index 08092a9e116..55d62108cba 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java @@ -21,6 +21,9 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.Location; +import java.util.Objects; +import java.util.Set; + /** * The superclass for all other nodes. */ @@ -31,9 +34,17 @@ public abstract class ANode { final Location location; ANode(Location location) { - this.location = location; + this.location = Objects.requireNonNull(location); } + /** + * Adds all variable names referenced to the variable set. + *

+ * This can be called at any time, e.g. to support lambda capture. + * @param variables set of variables referenced (any scope) + */ + abstract void extractVariables(Set variables); + public RuntimeException createError(RuntimeException exception) { return location.createError(exception); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java index 87b12284789..ca6332cd65e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java @@ -25,6 +25,10 @@ import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Type; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; @@ -48,9 +52,15 @@ public final class EBinary extends AExpression { public EBinary(Location location, Operation operation, AExpression left, AExpression right) { super(location); - this.operation = operation; - this.left = left; - this.right = right; + this.operation = Objects.requireNonNull(operation); + this.left = Objects.requireNonNull(left); + this.right = Objects.requireNonNull(right); + } + + @Override + void extractVariables(Set variables) { + left.extractVariables(variables); + right.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java index 9e39ca712f5..d707cc811f9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java @@ -25,6 +25,10 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.Locals; import org.objectweb.asm.Label; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -39,9 +43,15 @@ public final class EBool extends AExpression { public EBool(Location location, Operation operation, AExpression left, AExpression right) { super(location); - this.operation = operation; - this.left = left; - this.right = right; + this.operation = Objects.requireNonNull(operation); + this.left = Objects.requireNonNull(left); + this.right = Objects.requireNonNull(right); + } + + @Override + void extractVariables(Set variables) { + left.extractVariables(variables); + right.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java index a152422fac4..dc25bb0ed44 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java @@ -25,6 +25,8 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; +import java.util.Set; + /** * Represents a boolean constant. */ @@ -35,6 +37,9 @@ public final class EBoolean extends AExpression { this.constant = constant; } + + @Override + void extractVariables(Set variables) {} @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java index 62ecf63b9b3..aa7f807aff1 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java @@ -33,32 +33,39 @@ import org.objectweb.asm.Type; import static org.elasticsearch.painless.WriterConstants.LAMBDA_BOOTSTRAP_HANDLE; import java.lang.invoke.LambdaMetafactory; +import java.util.Objects; +import java.util.Set; /** * Represents a capturing function reference. */ public class ECapturingFunctionRef extends AExpression implements ILambda { - public final String type; + public final String variable; public final String call; private FunctionRef ref; Variable captured; String defPointer; - public ECapturingFunctionRef(Location location, String type, String call) { + public ECapturingFunctionRef(Location location, String variable, String call) { super(location); - this.type = type; - this.call = call; + this.variable = Objects.requireNonNull(variable); + this.call = Objects.requireNonNull(call); + } + + @Override + void extractVariables(Set variables) { + variables.add(variable); } @Override void analyze(Locals variables) { - captured = variables.getVariable(location, type); + captured = variables.getVariable(location, variable); if (expected == null) { if (captured.type.sort == Definition.Sort.DEF) { // dynamic implementation - defPointer = "D" + type + "." + call + ",1"; + defPointer = "D" + variable + "." + call + ",1"; } else { // typed implementation defPointer = "S" + captured.type.name + "." + call + ",1"; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java index 1073125c637..c7dda568ff5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java @@ -20,6 +20,10 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.Definition.Cast; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; @@ -40,9 +44,13 @@ final class ECast extends AExpression { super(location); this.type = null; - this.child = child; - - this.cast = cast; + this.child = Objects.requireNonNull(child); + this.cast = Objects.requireNonNull(cast); + } + + @Override + void extractVariables(Set variables) { + child.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EChain.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EChain.java index aa5bbcaab9d..44fe019990f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EChain.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EChain.java @@ -33,6 +33,8 @@ import org.elasticsearch.painless.MethodWriter; import java.util.Arrays; import java.util.List; +import java.util.Objects; +import java.util.Set; /** * Represents the entirety of a variable/method chain for read/write operations. @@ -60,12 +62,22 @@ public final class EChain extends AExpression { boolean pre, boolean post, Operation operation, AExpression expression) { super(location); - this.links = links; + this.links = Objects.requireNonNull(links); this.pre = pre; this.post = post; this.operation = operation; this.expression = expression; } + + @Override + void extractVariables(Set variables) { + for (ALink link : links) { + link.extractVariables(variables); + } + if (expression != null) { + expression.extractVariables(variables); + } + } @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java index 31050f9f6ce..d76fbbe9065 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java @@ -29,6 +29,10 @@ import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.Locals; import org.objectweb.asm.Label; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; import static org.elasticsearch.painless.WriterConstants.OBJECTS_TYPE; @@ -47,9 +51,15 @@ public final class EComp extends AExpression { public EComp(Location location, Operation operation, AExpression left, AExpression right) { super(location); - this.operation = operation; - this.left = left; - this.right = right; + this.operation = Objects.requireNonNull(operation); + this.left = Objects.requireNonNull(left); + this.right = Objects.requireNonNull(right); + } + + @Override + void extractVariables(Set variables) { + left.extractVariables(variables); + right.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java index 600626348dd..e05419e1c52 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java @@ -26,6 +26,10 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.Locals; import org.objectweb.asm.Label; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -40,9 +44,16 @@ public final class EConditional extends AExpression { public EConditional(Location location, AExpression condition, AExpression left, AExpression right) { super(location); - this.condition = condition; - this.left = left; - this.right = right; + this.condition = Objects.requireNonNull(condition); + this.left = Objects.requireNonNull(left); + this.right = Objects.requireNonNull(right); + } + + @Override + void extractVariables(Set variables) { + condition.extractVariables(variables); + left.extractVariables(variables); + right.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java index b037d25c2d6..c5e10a340d6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java @@ -22,6 +22,9 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Definition.Sort; + +import java.util.Set; + import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; @@ -37,6 +40,9 @@ final class EConstant extends AExpression { this.constant = constant; } + + @Override + void extractVariables(Set variables) {} @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java index efa453605cb..e93b63c3bcd 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java @@ -25,8 +25,11 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; +import java.util.Objects; +import java.util.Set; + /** - * Respresents a decimal constant. + * Represents a decimal constant. */ public final class EDecimal extends AExpression { @@ -35,8 +38,11 @@ public final class EDecimal extends AExpression { public EDecimal(Location location, String value) { super(location); - this.value = value; + this.value = Objects.requireNonNull(value); } + + @Override + void extractVariables(Set variables) {} @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java index 1c186faaeeb..71ad952baff 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java @@ -25,6 +25,9 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; +import java.util.Objects; +import java.util.Set; + /** * Represents an explicit cast. */ @@ -36,8 +39,13 @@ public final class EExplicit extends AExpression { public EExplicit(Location location, String type, AExpression child) { super(location); - this.type = type; - this.child = child; + this.type = Objects.requireNonNull(type); + this.child = Objects.requireNonNull(child); + } + + @Override + void extractVariables(Set variables) { + child.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java index 856a876550c..298b84ffe29 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java @@ -32,6 +32,8 @@ import org.objectweb.asm.Type; import static org.elasticsearch.painless.WriterConstants.LAMBDA_BOOTSTRAP_HANDLE; import java.lang.invoke.LambdaMetafactory; +import java.util.Objects; +import java.util.Set; /** * Represents a function reference. @@ -46,9 +48,12 @@ public class EFunctionRef extends AExpression implements ILambda { public EFunctionRef(Location location, String type, String call) { super(location); - this.type = type; - this.call = call; + this.type = Objects.requireNonNull(type); + this.call = Objects.requireNonNull(call); } + + @Override + void extractVariables(Set variables) {} @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java index d0b531c74d3..1d1498a51c4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java @@ -23,72 +23,194 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.node.SFunction.FunctionReserved; +import org.elasticsearch.painless.Definition; +import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import java.lang.invoke.LambdaMetafactory; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Objects; +import java.util.Set; +import static org.elasticsearch.painless.WriterConstants.LAMBDA_BOOTSTRAP_HANDLE; + +/** + * Lambda expression node. + *

+ * This can currently only be the direct argument of a call (method/constructor). + * When the argument is of a known type, it uses + * + * Java's lambda translation. However, if its a def call, then we don't have + * enough information, and have to defer this until link time. In that case a placeholder + * and all captures are pushed onto the stack and folded into the signature of the parent call. + *

+ * For example: + *
+ * {@code def list = new ArrayList(); int capture = 0; list.sort((x,y) -> x - y + capture)} + *
+ * is converted into a call (pseudocode) such as: + *
+ * {@code sort(list, lambda$0, capture)} + *
+ * At link time, when we know the interface type, this is decomposed with MethodHandle + * combinators back into (pseudocode): + *
+ * {@code sort(list, lambda$0(capture))} + */ public class ELambda extends AExpression implements ILambda { final String name; final FunctionReserved reserved; final List paramTypeStrs; final List paramNameStrs; final List statements; + // desugared synthetic method (lambda body) SFunction desugared; - // method ref (impl detail) - ILambda impl; + // captured variables + List captures; + // static parent, static lambda + FunctionRef ref; + // dynamic parent, deferred until link time + String defPointer; public ELambda(String name, FunctionReserved reserved, Location location, List paramTypes, List paramNames, List statements) { super(location); - this.name = name; - this.reserved = reserved; + this.name = Objects.requireNonNull(name); + this.reserved = Objects.requireNonNull(reserved); this.paramTypeStrs = Collections.unmodifiableList(paramTypes); this.paramNameStrs = Collections.unmodifiableList(paramNames); this.statements = Collections.unmodifiableList(statements); } + + @Override + void extractVariables(Set variables) { + for (AStatement statement : statements) { + statement.extractVariables(variables); + } + } @Override void analyze(Locals locals) { + // gather any variables used by the lambda body first. + Set variables = new HashSet<>(); + for (AStatement statement : statements) { + statement.extractVariables(variables); + } + // any of those variables defined in our scope need to be captured + captures = new ArrayList<>(); + for (String variable : variables) { + if (locals.hasVariable(variable)) { + captures.add(locals.getVariable(location, variable)); + } + } + // prepend capture list to lambda's arguments + List paramTypes = new ArrayList<>(); + List paramNames = new ArrayList<>(); + for (Variable var : captures) { + paramTypes.add(var.type.name); + paramNames.add(var.name); + } + paramTypes.addAll(paramTypeStrs); + paramNames.addAll(paramNameStrs); + // desugar lambda body into a synthetic method desugared = new SFunction(reserved, location, "def", name, - paramTypeStrs, paramNameStrs, statements, true); + paramTypes, paramNames, statements, true); desugared.generate(); - List captures = new ArrayList<>(); - desugared.analyze(Locals.newLambdaScope(locals.getProgramScope(), desugared.parameters, captures)); + desugared.analyze(Locals.newLambdaScope(locals.getProgramScope(), desugared.parameters, + captures.size(), reserved.getMaxLoopCounter())); - // setup reference - EFunctionRef ref = new EFunctionRef(location, "this", name); - ref.expected = expected; - // hack, create a new scope, with our method, so the ref can see it (impl detail) - locals = Locals.newLocalScope(locals); - locals.addMethod(desugared.method); - ref.analyze(locals); - actual = ref.actual; - impl = ref; + // setup method reference to synthetic method + if (expected == null) { + ref = null; + actual = Definition.getType("String"); + defPointer = "Sthis." + name + "," + captures.size(); + } else { + defPointer = null; + try { + Method interfaceMethod = expected.struct.getFunctionalMethod(); + if (interfaceMethod == null) { + throw new IllegalArgumentException("Cannot pass lambda to [" + expected.name + + "], not a functional interface"); + } + Class captureClasses[] = new Class[captures.size()]; + for (int i = 0; i < captures.size(); i++) { + captureClasses[i] = captures.get(i).type.clazz; + } + ref = new FunctionRef(expected, interfaceMethod, desugared.method, captureClasses); + } catch (IllegalArgumentException e) { + throw createError(e); + } + actual = expected; + } } @Override void write(MethodWriter writer, Globals globals) { - AExpression expr = (AExpression) impl; - expr.write(writer, globals); + writer.writeDebugInfo(location); + + if (ref != null) { + writer.writeDebugInfo(location); + // load captures + for (Variable capture : captures) { + writer.visitVarInsn(capture.type.type.getOpcode(Opcodes.ILOAD), capture.getSlot()); + } + // convert MethodTypes to asm Type for the constant pool. + String invokedType = ref.invokedType.toMethodDescriptorString(); + Type samMethodType = Type.getMethodType(ref.samMethodType.toMethodDescriptorString()); + Type interfaceType = Type.getMethodType(ref.interfaceMethodType.toMethodDescriptorString()); + if (ref.needsBridges()) { + writer.invokeDynamic(ref.invokedName, + invokedType, + LAMBDA_BOOTSTRAP_HANDLE, + samMethodType, + ref.implMethodASM, + samMethodType, + LambdaMetafactory.FLAG_BRIDGES, + 1, + interfaceType); + } else { + writer.invokeDynamic(ref.invokedName, + invokedType, + LAMBDA_BOOTSTRAP_HANDLE, + samMethodType, + ref.implMethodASM, + samMethodType, + 0); + } + } else { + // placeholder + writer.push((String)null); + // load captures + for (Variable capture : captures) { + writer.visitVarInsn(capture.type.type.getOpcode(Opcodes.ILOAD), capture.getSlot()); + } + } + // add synthetic method to the queue to be written globals.addSyntheticMethod(desugared); } @Override public String getPointer() { - return impl.getPointer(); + return defPointer; } @Override public Type[] getCaptures() { - return impl.getCaptures(); + Type[] types = new Type[captures.size()]; + for (int i = 0; i < types.length; i++) { + types[i] = captures.get(i).type.type; + } + return types; } - } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java index 0a1242e6507..ad6562c0e14 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java @@ -24,6 +24,9 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.objectweb.asm.Opcodes; + +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -34,6 +37,9 @@ public final class ENull extends AExpression { public ENull(Location location) { super(location); } + + @Override + void extractVariables(Set variables) {} @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java index e2314880448..e9a28a1e06a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java @@ -23,6 +23,10 @@ import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Definition.Sort; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; @@ -37,9 +41,12 @@ public final class ENumeric extends AExpression { public ENumeric(Location location, String value, int radix) { super(location); - this.value = value; + this.value = Objects.requireNonNull(value); this.radix = radix; } + + @Override + void extractVariables(Set variables) {} @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java index 40776811b67..a635ec811a3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java @@ -29,6 +29,10 @@ import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.Locals; import org.objectweb.asm.Label; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -44,8 +48,13 @@ public final class EUnary extends AExpression { public EUnary(Location location, Operation operation, AExpression child) { super(location); - this.operation = operation; - this.child = child; + this.operation = Objects.requireNonNull(operation); + this.child = Objects.requireNonNull(child); + } + + @Override + void extractVariables(Set variables) { + child.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LArrayLength.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LArrayLength.java index 1a240747d73..a2970ca2e53 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LArrayLength.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LArrayLength.java @@ -25,6 +25,9 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; +import java.util.Objects; +import java.util.Set; + /** * Represents an array length field load. */ @@ -35,8 +38,11 @@ public final class LArrayLength extends ALink { LArrayLength(Location location, String value) { super(location, -1); - this.value = value; + this.value = Objects.requireNonNull(value); } + + @Override + void extractVariables(Set variables) {} @Override ALink analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LBrace.java index e8c23bf3857..16b9b8c5d44 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LBrace.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LBrace.java @@ -28,6 +28,8 @@ import org.elasticsearch.painless.MethodWriter; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; /** * Represents an array load/store or defers to possible shortcuts. @@ -39,7 +41,12 @@ public final class LBrace extends ALink { public LBrace(Location location, AExpression index) { super(location, 2); - this.index = index; + this.index = Objects.requireNonNull(index); + } + + @Override + void extractVariables(Set variables) { + index.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCallInvoke.java index 34ad0343aa9..124755780cb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCallInvoke.java @@ -29,9 +29,11 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; import java.util.List; +import java.util.Objects; +import java.util.Set; /** - * Represents a method call or deferes to a def call. + * Represents a method call or defers to a def call. */ public final class LCallInvoke extends ALink { @@ -43,8 +45,15 @@ public final class LCallInvoke extends ALink { public LCallInvoke(Location location, String name, List arguments) { super(location, -1); - this.name = name; - this.arguments = arguments; + this.name = Objects.requireNonNull(name); + this.arguments = Objects.requireNonNull(arguments); + } + + @Override + void extractVariables(Set variables) { + for (AExpression argument : arguments) { + argument.extractVariables(variables); + } } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCallLocal.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCallLocal.java index 4503692b48d..7aa46f004d6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCallLocal.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCallLocal.java @@ -27,6 +27,8 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import java.util.List; +import java.util.Objects; +import java.util.Set; import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE; @@ -43,8 +45,15 @@ public class LCallLocal extends ALink { public LCallLocal(Location location, String name, List arguments) { super(location, -1); - this.name = name; - this.arguments = arguments; + this.name = Objects.requireNonNull(name); + this.arguments = Objects.requireNonNull(arguments); + } + + @Override + void extractVariables(Set variables) { + for (AExpression argument : arguments) { + argument.extractVariables(variables); + } } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCast.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCast.java index bf900cedafc..86dbdda24c4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCast.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCast.java @@ -23,6 +23,9 @@ import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Definition.Cast; + +import java.util.Set; + import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; @@ -41,6 +44,9 @@ public final class LCast extends ALink { this.type = type; } + + @Override + void extractVariables(Set variables) {} @Override ALink analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java index 93fd21f00b0..828e0a1cd8a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java @@ -25,6 +25,10 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Locals; import org.objectweb.asm.Type; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -37,7 +41,12 @@ final class LDefArray extends ALink implements IDefLink { LDefArray(Location location, AExpression index) { super(location, 2); - this.index = index; + this.index = Objects.requireNonNull(index); + } + + @Override + void extractVariables(Set variables) { + index.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java index b104ce732ae..dfdaef2369f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java @@ -29,6 +29,8 @@ import org.objectweb.asm.Type; import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import java.util.Set; /** * Represents a method call made on a def type. (Internal only.) @@ -37,26 +39,26 @@ final class LDefCall extends ALink implements IDefLink { final String name; final List arguments; - long recipe; + StringBuilder recipe; List pointers = new ArrayList<>(); LDefCall(Location location, String name, List arguments) { super(location, -1); - this.name = name; - this.arguments = arguments; + this.name = Objects.requireNonNull(name); + this.arguments = Objects.requireNonNull(arguments); + } + + @Override + void extractVariables(Set variables) { + for (AExpression argument : arguments) { + argument.extractVariables(variables); + } } @Override ALink analyze(Locals locals) { - if (arguments.size() > 63) { - // technically, the limitation is just methods with > 63 params, containing method references. - // this is because we are lazy and use a long as a bitset. we can always change to a "string" if need be. - // but NEED NOT BE. nothing with this many parameters is in the whitelist and we do not support varargs. - throw new UnsupportedOperationException("methods with > 63 arguments are currently not supported"); - } - - recipe = 0; + recipe = new StringBuilder(); int totalCaptures = 0; for (int argument = 0; argument < arguments.size(); ++argument) { AExpression expression = arguments.get(argument); @@ -67,7 +69,9 @@ final class LDefCall extends ALink implements IDefLink { if (expression instanceof ILambda) { ILambda lambda = (ILambda) expression; pointers.add(lambda.getPointer()); - recipe |= (1L << (argument + totalCaptures)); // mark argument as deferred reference + // encode this parameter as a deferred reference + char ch = (char) (argument + totalCaptures); + recipe.append(ch); totalCaptures += lambda.getCaptureCount(); } @@ -111,7 +115,7 @@ final class LDefCall extends ALink implements IDefLink { Type methodType = Type.getMethodType(after.type, parameterTypes.toArray(new Type[0])); List args = new ArrayList<>(); - args.add(recipe); + args.add(recipe.toString()); args.addAll(pointers); writer.invokeDefCall(name, methodType, DefBootstrap.METHOD_CALL, args.toArray()); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java index ba474764cd0..c51a0a02647 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java @@ -25,6 +25,10 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Locals; import org.objectweb.asm.Type; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -37,9 +41,11 @@ final class LDefField extends ALink implements IDefLink { LDefField(Location location, String value) { super(location, 1); - this.value = value; + this.value = Objects.requireNonNull(value); } + @Override + void extractVariables(Set variables) {} @Override ALink analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LField.java index 9fc48c009a2..30d0a033746 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LField.java @@ -30,6 +30,8 @@ import org.elasticsearch.painless.MethodWriter; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; /** * Represents a field load/store or defers to a possible shortcuts. @@ -43,8 +45,11 @@ public final class LField extends ALink { public LField(Location location, String value) { super(location, 1); - this.value = value; + this.value = Objects.requireNonNull(value); } + + @Override + void extractVariables(Set variables) {} @Override ALink analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LListShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LListShortcut.java index 1cd5620cc17..f2863ce3396 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LListShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LListShortcut.java @@ -24,6 +24,10 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Sort; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; @@ -39,7 +43,12 @@ final class LListShortcut extends ALink { LListShortcut(Location location, AExpression index) { super(location, 2); - this.index = index; + this.index = Objects.requireNonNull(index); + } + + @Override + void extractVariables(Set variables) { + index.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LMapShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LMapShortcut.java index 05c2192b870..3bc9ab57a37 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LMapShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LMapShortcut.java @@ -24,6 +24,10 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Sort; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; @@ -39,7 +43,12 @@ final class LMapShortcut extends ALink { LMapShortcut(Location location, AExpression index) { super(location, 2); - this.index = index; + this.index = Objects.requireNonNull(index); + } + + @Override + void extractVariables(Set variables) { + index.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewArray.java index 312cbf925e1..cf83599210f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewArray.java @@ -27,6 +27,8 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; import java.util.List; +import java.util.Objects; +import java.util.Set; /** * Represents an array instantiation. @@ -39,8 +41,15 @@ public final class LNewArray extends ALink { public LNewArray(Location location, String type, List arguments) { super(location, -1); - this.type = type; - this.arguments = arguments; + this.type = Objects.requireNonNull(type); + this.arguments = Objects.requireNonNull(arguments); + } + + @Override + void extractVariables(Set variables) { + for (AExpression argument : arguments) { + argument.extractVariables(variables); + } } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewObj.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewObj.java index 0b28a308e19..0ac2762f336 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewObj.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewObj.java @@ -29,6 +29,8 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; import java.util.List; +import java.util.Objects; +import java.util.Set; /** * Represents and object instantiation. @@ -43,8 +45,15 @@ public final class LNewObj extends ALink { public LNewObj(Location location, String type, List arguments) { super(location, -1); - this.type = type; - this.arguments = arguments; + this.type = Objects.requireNonNull(type); + this.arguments = Objects.requireNonNull(arguments); + } + + @Override + void extractVariables(Set variables) { + for (AExpression argument : arguments) { + argument.extractVariables(variables); + } } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LRegex.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LRegex.java index 8727f992242..c737c761cf2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LRegex.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LRegex.java @@ -24,6 +24,7 @@ import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; +import java.util.Set; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -54,6 +55,9 @@ public final class LRegex extends ALink { throw createError(e); } } + + @Override + void extractVariables(Set variables) {} @Override ALink analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LShortcut.java index efaf02bb601..7f97b446382 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LShortcut.java @@ -25,6 +25,10 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Struct; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; @@ -41,8 +45,11 @@ final class LShortcut extends ALink { LShortcut(Location location, String value) { super(location, 1); - this.value = value; + this.value = Objects.requireNonNull(value); } + + @Override + void extractVariables(Set variables) {} @Override ALink analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LStatic.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LStatic.java index 3a7c9a35fe5..d9077a4446f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LStatic.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LStatic.java @@ -23,6 +23,10 @@ import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.Locals; /** @@ -35,8 +39,11 @@ public final class LStatic extends ALink { public LStatic(Location location, String type) { super(location, 0); - this.type = type; + this.type = Objects.requireNonNull(type); } + + @Override + void extractVariables(Set variables) {} @Override ALink analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LString.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LString.java index fac9d413ad7..ab45c0f3a8e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LString.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LString.java @@ -25,6 +25,9 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; +import java.util.Objects; +import java.util.Set; + /** * Represents a string constant. */ @@ -33,8 +36,11 @@ public final class LString extends ALink { public LString(Location location, String string) { super(location, -1); - this.string = string; + this.string = Objects.requireNonNull(string); } + + @Override + void extractVariables(Set variables) {} @Override ALink analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LVariable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LVariable.java index ad9ba9dfbf6..4f016349c24 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LVariable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LVariable.java @@ -26,6 +26,9 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.objectweb.asm.Opcodes; +import java.util.Objects; +import java.util.Set; + /** * Represents a variable load/store. */ @@ -38,7 +41,12 @@ public final class LVariable extends ALink { public LVariable(Location location, String name) { super(location, 0); - this.name = name; + this.name = Objects.requireNonNull(name); + } + + @Override + void extractVariables(Set variables) { + variables.add(name); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java index 7d459f27504..e688f0acec0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java @@ -26,6 +26,7 @@ import org.elasticsearch.painless.MethodWriter; import java.util.Collections; import java.util.List; +import java.util.Set; /** * Represents a set of statements as a branch of control-flow. @@ -39,6 +40,13 @@ public final class SBlock extends AStatement { this.statements = Collections.unmodifiableList(statements); } + + @Override + void extractVariables(Set variables) { + for (AStatement statement : statements) { + statement.extractVariables(variables); + } + } @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java index c791faeadd6..62560d1bd4e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java @@ -24,6 +24,8 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import java.util.Set; + /** * Represents a break statement. */ @@ -32,6 +34,9 @@ public final class SBreak extends AStatement { public SBreak(Location location) { super(location); } + + @Override + void extractVariables(Set variables) {} @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java index 8632c0eea6d..783af3d0022 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java @@ -27,6 +27,10 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -47,10 +51,18 @@ public final class SCatch extends AStatement { public SCatch(Location location, String type, String name, SBlock block) { super(location); - this.type = type; - this.name = name; + this.type = Objects.requireNonNull(type); + this.name = Objects.requireNonNull(name); this.block = block; } + + @Override + void extractVariables(Set variables) { + variables.add(name); + if (block != null) { + block.extractVariables(variables); + } + } @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java index e70f625bb3d..98ac804cc3a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java @@ -24,6 +24,8 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import java.util.Set; + /** * Represents a continue statement. */ @@ -32,6 +34,9 @@ public final class SContinue extends AStatement { public SContinue(Location location) { super(location); } + + @Override + void extractVariables(Set variables) {} @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java index 58ff09e45d8..d0dae5a68ac 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java @@ -26,6 +26,7 @@ import org.elasticsearch.painless.MethodWriter; import java.util.Collections; import java.util.List; +import java.util.Set; /** * Represents a series of declarations. @@ -39,6 +40,13 @@ public final class SDeclBlock extends AStatement { this.declarations = Collections.unmodifiableList(declarations); } + + @Override + void extractVariables(Set variables) { + for (SDeclaration declaration : declarations) { + declaration.extractVariables(variables); + } + } @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java index c19adfd699e..de856722a0a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java @@ -26,6 +26,10 @@ import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.objectweb.asm.Opcodes; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -42,10 +46,18 @@ public final class SDeclaration extends AStatement { public SDeclaration(Location location, String type, String name, AExpression expression) { super(location); - this.type = type; - this.name = name; + this.type = Objects.requireNonNull(type); + this.name = Objects.requireNonNull(name); this.expression = expression; } + + @Override + void extractVariables(Set variables) { + variables.add(name); + if (expression != null) { + expression.extractVariables(variables); + } + } @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java index 3b94f5799ea..e214703daf4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java @@ -24,6 +24,10 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.objectweb.asm.Label; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -37,9 +41,17 @@ public final class SDo extends AStatement { public SDo(Location location, SBlock block, AExpression condition) { super(location); - this.condition = condition; + this.condition = Objects.requireNonNull(condition); this.block = block; } + + @Override + void extractVariables(Set variables) { + condition.extractVariables(variables); + if (block != null) { + block.extractVariables(variables); + } + } @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java index 96258de0760..a90baac3203 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java @@ -35,6 +35,9 @@ import org.elasticsearch.painless.Locals.Variable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; +import java.util.Objects; +import java.util.Set; + import static org.elasticsearch.painless.WriterConstants.ITERATOR_HASNEXT; import static org.elasticsearch.painless.WriterConstants.ITERATOR_NEXT; import static org.elasticsearch.painless.WriterConstants.ITERATOR_TYPE; @@ -65,11 +68,20 @@ public class SEach extends AStatement { public SEach(Location location, String type, String name, AExpression expression, SBlock block) { super(location); - this.type = type; - this.name = name; - this.expression = expression; + this.type = Objects.requireNonNull(type); + this.name = Objects.requireNonNull(name); + this.expression = Objects.requireNonNull(expression); this.block = block; } + + @Override + void extractVariables(Set variables) { + variables.add(name); + expression.extractVariables(variables); + if (block != null) { + block.extractVariables(variables); + } + } @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java index c6cf0a47c8f..94eb180ea03 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java @@ -20,6 +20,10 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.Definition.Type; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Globals; @@ -36,7 +40,12 @@ public final class SExpression extends AStatement { public SExpression(Location location, AExpression expression) { super(location); - this.expression = expression; + this.expression = Objects.requireNonNull(expression); + } + + @Override + void extractVariables(Set variables) { + expression.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java index b2cf1da2594..06ad19d204d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java @@ -24,6 +24,9 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.objectweb.asm.Label; + +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -44,6 +47,22 @@ public final class SFor extends AStatement { this.afterthought = afterthought; this.block = block; } + + @Override + void extractVariables(Set variables) { + if (initializer != null) { + initializer.extractVariables(variables); + } + if (condition != null) { + condition.extractVariables(variables); + } + if (afterthought != null) { + afterthought.extractVariables(variables); + } + if (block != null) { + block.extractVariables(variables); + } + } @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java index 2426508d096..ba078d03dbd 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java @@ -42,6 +42,8 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.Set; import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE; @@ -68,14 +70,20 @@ public class SFunction extends AStatement { List paramNames, List statements, boolean synthetic) { super(location); - this.reserved = reserved; - this.rtnTypeStr = rtnType; - this.name = name; + this.reserved = Objects.requireNonNull(reserved); + this.rtnTypeStr = Objects.requireNonNull(rtnType); + this.name = Objects.requireNonNull(name); this.paramTypeStrs = Collections.unmodifiableList(paramTypes); this.paramNameStrs = Collections.unmodifiableList(paramNames); this.statements = Collections.unmodifiableList(statements); this.synthetic = synthetic; } + + @Override + void extractVariables(Set variables) { + // we should never be extracting from a function, as functions are top-level! + throw new IllegalStateException("Illegal tree structure"); + } void generate() { try { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java index 1b0c0ffb348..eb862b1177a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java @@ -24,6 +24,10 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.objectweb.asm.Label; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -37,9 +41,17 @@ public final class SIf extends AStatement { public SIf(Location location, AExpression condition, SBlock ifblock) { super(location); - this.condition = condition; + this.condition = Objects.requireNonNull(condition); this.ifblock = ifblock; } + + @Override + void extractVariables(Set variables) { + condition.extractVariables(variables); + if (ifblock != null) { + ifblock.extractVariables(variables); + } + } @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java index 612969acfff..8296ddcada0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java @@ -24,6 +24,10 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.objectweb.asm.Label; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -38,10 +42,21 @@ public final class SIfElse extends AStatement { public SIfElse(Location location, AExpression condition, SBlock ifblock, SBlock elseblock) { super(location); - this.condition = condition; + this.condition = Objects.requireNonNull(condition); this.ifblock = ifblock; this.elseblock = elseblock; } + + @Override + void extractVariables(Set variables) { + condition.extractVariables(variables); + if (ifblock != null) { + ifblock.extractVariables(variables); + } + if (elseblock != null) { + elseblock.extractVariables(variables); + } + } @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SReturn.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SReturn.java index 2c46b3ecfaf..36e629ca6d8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SReturn.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SReturn.java @@ -24,6 +24,9 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; +import java.util.Objects; +import java.util.Set; + /** * Represents a return statement. */ @@ -34,7 +37,12 @@ public final class SReturn extends AStatement { public SReturn(Location location, AExpression expression) { super(location); - this.expression = expression; + this.expression = Objects.requireNonNull(expression); + } + + @Override + void extractVariables(Set variables) { + expression.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java index 6b870c7367d..950b021486f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java @@ -44,6 +44,8 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; import static org.elasticsearch.painless.WriterConstants.BASE_CLASS_TYPE; import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE; @@ -73,11 +75,11 @@ public final class SSource extends AStatement { MainMethodReserved reserved, Location location, List functions, Globals globals, List statements) { super(location); - this.settings = settings; - this.name = name; - this.source = source; + this.settings = Objects.requireNonNull(settings); + this.name = Objects.requireNonNull(name); + this.source = Objects.requireNonNull(source); this.debugStream = debugStream; - this.reserved = reserved; + this.reserved = Objects.requireNonNull(reserved); // process any synthetic functions generated by walker (because right now, thats still easy) functions.addAll(globals.getSyntheticMethods().values()); globals.getSyntheticMethods().clear(); @@ -85,6 +87,12 @@ public final class SSource extends AStatement { this.statements = Collections.unmodifiableList(statements); this.globals = globals; } + + @Override + void extractVariables(Set variables) { + // we should never be extracting from a function, as functions are top-level! + throw new IllegalStateException("Illegal tree structure"); + } public void analyze() { Map methods = new HashMap<>(); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java index ffa1b89dfe2..c78e0503f30 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java @@ -25,6 +25,9 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.MethodWriter; +import java.util.Objects; +import java.util.Set; + /** * Represents a throw statement. */ @@ -35,7 +38,12 @@ public final class SThrow extends AStatement { public SThrow(Location location, AExpression expression) { super(location); - this.expression = expression; + this.expression = Objects.requireNonNull(expression); + } + + @Override + void extractVariables(Set variables) { + expression.extractVariables(variables); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java index 0295d32ae35..1986b5eeb66 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java @@ -27,6 +27,7 @@ import org.elasticsearch.painless.MethodWriter; import java.util.Collections; import java.util.List; +import java.util.Set; /** * Represents the try block as part of a try-catch block. @@ -42,6 +43,16 @@ public final class STry extends AStatement { this.block = block; this.catches = Collections.unmodifiableList(catches); } + + @Override + void extractVariables(Set variables) { + if (block != null) { + block.extractVariables(variables); + } + for (SCatch expr : catches) { + expr.extractVariables(variables); + } + } @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java index 39b48781b46..dff8ae2592f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java @@ -24,6 +24,10 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Locals; import org.objectweb.asm.Label; + +import java.util.Objects; +import java.util.Set; + import org.elasticsearch.painless.MethodWriter; /** @@ -37,9 +41,17 @@ public final class SWhile extends AStatement { public SWhile(Location location, AExpression condition, SBlock block) { super(location); - this.condition = condition; + this.condition = Objects.requireNonNull(condition); this.block = block; } + + @Override + void extractVariables(Set variables) { + condition.extractVariables(variables); + if (block != null) { + block.extractVariables(variables); + } + } @Override void analyze(Locals locals) { diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/ArrayTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/ArrayTests.java index e6a5537194d..acacc613ab3 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/ArrayTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/ArrayTests.java @@ -19,6 +19,9 @@ package org.elasticsearch.painless; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; + /** Tests for or operator across all types */ public class ArrayTests extends ScriptTestCase { @@ -36,7 +39,10 @@ public class ArrayTests extends ScriptTestCase { } private void assertArrayLength(int length, Object array) throws Throwable { - assertEquals(length, (int) Def.arrayLengthGetter(array.getClass()).invoke(array)); + final MethodHandle mh = Def.arrayLengthGetter(array.getClass()); + assertSame(array.getClass(), mh.type().parameterType(0)); + assertEquals(length, (int) mh.asType(MethodType.methodType(int.class, Object.class)) + .invokeExact(array)); } public void testArrayLoadStoreInt() { diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java index 6babe51334a..68d184cb173 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java @@ -37,7 +37,7 @@ public class DefBootstrapTests extends ESTestCase { "toString", MethodType.methodType(String.class, Object.class), 0, - DefBootstrap.METHOD_CALL, 0L); + DefBootstrap.METHOD_CALL, ""); MethodHandle handle = site.dynamicInvoker(); assertDepthEquals(site, 0); @@ -55,7 +55,7 @@ public class DefBootstrapTests extends ESTestCase { "toString", MethodType.methodType(String.class, Object.class), 0, - DefBootstrap.METHOD_CALL, 0L); + DefBootstrap.METHOD_CALL, ""); MethodHandle handle = site.dynamicInvoker(); assertDepthEquals(site, 0); @@ -78,7 +78,7 @@ public class DefBootstrapTests extends ESTestCase { "toString", MethodType.methodType(String.class, Object.class), 0, - DefBootstrap.METHOD_CALL, 0L); + DefBootstrap.METHOD_CALL, ""); MethodHandle handle = site.dynamicInvoker(); assertDepthEquals(site, 0); @@ -102,7 +102,7 @@ public class DefBootstrapTests extends ESTestCase { "size", MethodType.methodType(int.class, Object.class), 0, - DefBootstrap.METHOD_CALL, 0L); + DefBootstrap.METHOD_CALL, ""); site.depth = DefBootstrap.PIC.MAX_DEPTH; // mark megamorphic MethodHandle handle = site.dynamicInvoker(); assertEquals(2, (int)handle.invokeExact((Object) Arrays.asList("1", "2"))); @@ -145,7 +145,7 @@ public class DefBootstrapTests extends ESTestCase { DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL); MethodHandle handle = site.dynamicInvoker(); assertEquals(2, (Object)handle.invokeExact((Object)1, (Object)1)); - assertEquals("nulltest", (Object)handle.invoke((Object)null, (Object)"test")); + assertEquals("nulltest", (Object)handle.invokeExact((Object)null, (Object)"test")); } public void testNullGuardEq() throws Throwable { diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionRefTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionRefTests.java index 8ed2f3261cf..46d2b7c43fd 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionRefTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionRefTests.java @@ -162,4 +162,18 @@ public class FunctionRefTests extends ScriptTestCase { exec("List l = new ArrayList(); l.add(2); l.add(1); l.sort(String::startsWith); return l.get(0);"); }); } + + public void testWrongArity() { + IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> { + exec("Optional.empty().orElseGet(String::startsWith);"); + }); + assertTrue(expected.getMessage().contains("Unknown reference")); + } + + public void testWrongArityDef() { + IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> { + exec("def y = Optional.empty(); return y.orElseGet(String::startsWith);"); + }); + assertTrue(expected.getMessage().contains("Unknown reference")); + } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/LambdaTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/LambdaTests.java index dada9a9bc37..7b2d5e6a935 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/LambdaTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/LambdaTests.java @@ -85,6 +85,24 @@ public class LambdaTests extends ScriptTestCase { public void testUnneededCurlyStatements() { assertEquals(2, exec("int applyOne(IntFunction arg) { arg.apply(1) } applyOne(x -> { x + 1 })")); } + + /** interface ignores return value */ + public void testVoidReturn() { + assertEquals(2, exec("List list = new ArrayList(); " + + "list.add(2); " + + "List list2 = new ArrayList(); " + + "list.forEach(x -> list2.add(x));" + + "return list[0]")); + } + + /** interface ignores return value */ + public void testVoidReturnDef() { + assertEquals(2, exec("def list = new ArrayList(); " + + "list.add(2); " + + "List list2 = new ArrayList(); " + + "list.forEach(x -> list2.add(x));" + + "return list[0]")); + } public void testTwoLambdas() { assertEquals("testingcdefg", exec( @@ -103,4 +121,70 @@ public class LambdaTests extends ScriptTestCase { "}" + "return sum;")); } + + public void testCapture() { + assertEquals(5, exec("int x = 5; return Optional.empty().orElseGet(() -> x);")); + } + + public void testTwoCaptures() { + assertEquals("1test", exec("int x = 1; String y = 'test'; return Optional.empty().orElseGet(() -> x + y);")); + } + + public void testCapturesAreReadOnly() { + IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> { + exec("List l = new ArrayList(); l.add(1); l.add(1); " + + "return l.stream().mapToInt(x -> { l = null; return x + 1 }).sum();"); + }); + assertTrue(expected.getMessage().contains("is read-only")); + } + + public void testOnlyCapturesAreReadOnly() { + assertEquals(4, exec("List l = new ArrayList(); l.add(1); l.add(1); " + + "return l.stream().mapToInt(x -> { x += 1; return x }).sum();")); + } + + /** Lambda parameters shouldn't be able to mask a variable already in scope */ + public void testNoParamMasking() { + IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> { + exec("int x = 0; List l = new ArrayList(); l.add(1); l.add(1); " + + "return l.stream().mapToInt(x -> { x += 1; return x }).sum();"); + }); + assertTrue(expected.getMessage().contains("already defined")); + } + + public void testCaptureDef() { + assertEquals(5, exec("int x = 5; def y = Optional.empty(); y.orElseGet(() -> x);")); + } + + public void testNestedCapture() { + assertEquals(1, exec("boolean x = false; int y = 1;" + + "return Optional.empty().orElseGet(() -> x ? 5 : Optional.empty().orElseGet(() -> y));")); + } + + public void testNestedCaptureParams() { + assertEquals(2, exec("int foo(Function f) { return f.apply(1) }" + + "return foo(x -> foo(y -> x + 1))")); + } + + public void testWrongArity() { + IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> { + exec("Optional.empty().orElseGet(x -> x);"); + }); + assertTrue(expected.getMessage().contains("Incorrect number of parameters")); + } + + public void testWrongArityDef() { + IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> { + exec("def y = Optional.empty(); return y.orElseGet(x -> x);"); + }); + assertTrue(expected.getMessage(), expected.getMessage().contains("Incorrect number of parameters")); + } + + public void testLambdaInFunction() { + assertEquals(5, exec("def foo() { Optional.empty().orElseGet(() -> 5) } return foo();")); + } + + public void testLambdaCaptureFunctionParam() { + assertEquals(5, exec("def foo(int x) { Optional.empty().orElseGet(() -> x) } return foo(5);")); + } } diff --git a/plugins/discovery-azure/src/main/java/org/elasticsearch/discovery/azure/AzureUnicastHostsProvider.java b/plugins/discovery-azure/src/main/java/org/elasticsearch/discovery/azure/AzureUnicastHostsProvider.java index 869fda5f8e2..cb6c8238bf5 100644 --- a/plugins/discovery-azure/src/main/java/org/elasticsearch/discovery/azure/AzureUnicastHostsProvider.java +++ b/plugins/discovery-azure/src/main/java/org/elasticsearch/discovery/azure/AzureUnicastHostsProvider.java @@ -101,7 +101,6 @@ public class AzureUnicastHostsProvider extends AbstractComponent implements Unic private final AzureComputeService azureComputeService; private TransportService transportService; private NetworkService networkService; - private final Version version; private final TimeValue refreshInterval; private long lastRefresh; @@ -114,13 +113,11 @@ public class AzureUnicastHostsProvider extends AbstractComponent implements Unic @Inject public AzureUnicastHostsProvider(Settings settings, AzureComputeService azureComputeService, TransportService transportService, - NetworkService networkService, - Version version) { + NetworkService networkService) { super(settings); this.azureComputeService = azureComputeService; this.transportService = transportService; this.networkService = networkService; - this.version = version; this.refreshInterval = Discovery.REFRESH_SETTING.get(settings); @@ -253,7 +250,7 @@ public class AzureUnicastHostsProvider extends AbstractComponent implements Unic for (TransportAddress address : addresses) { logger.trace("adding {}, transport_address {}", networkAddress, address); cachedDiscoNodes.add(new DiscoveryNode("#cloud-" + instance.getInstanceName(), address, emptyMap(), - emptySet(), version.minimumCompatibilityVersion())); + emptySet(), Version.CURRENT.minimumCompatibilityVersion())); } } catch (Exception e) { logger.warn("can not convert [{}] to transport address. skipping. [{}]", networkAddress, e.getMessage()); diff --git a/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/AwsEc2UnicastHostsProvider.java b/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/AwsEc2UnicastHostsProvider.java index 58be8645131..1f3043fe6dd 100644 --- a/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/AwsEc2UnicastHostsProvider.java +++ b/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/AwsEc2UnicastHostsProvider.java @@ -59,8 +59,6 @@ public class AwsEc2UnicastHostsProvider extends AbstractComponent implements Uni private final AmazonEC2 client; - private final Version version; - private final boolean bindAnyGroup; private final Set groups; @@ -74,11 +72,10 @@ public class AwsEc2UnicastHostsProvider extends AbstractComponent implements Uni private final DiscoNodesCache discoNodes; @Inject - public AwsEc2UnicastHostsProvider(Settings settings, TransportService transportService, AwsEc2Service awsEc2Service, Version version) { + public AwsEc2UnicastHostsProvider(Settings settings, TransportService transportService, AwsEc2Service awsEc2Service) { super(settings); this.transportService = transportService; this.client = awsEc2Service.client(); - this.version = version; this.hostType = DISCOVERY_EC2.HOST_TYPE_SETTING.get(settings); this.discoNodes = new DiscoNodesCache(DISCOVERY_EC2.NODE_CACHE_TIME_SETTING.get(settings)); @@ -175,7 +172,7 @@ public class AwsEc2UnicastHostsProvider extends AbstractComponent implements Uni for (int i = 0; i < addresses.length; i++) { logger.trace("adding {}, address {}, transport_address {}", instance.getInstanceId(), address, addresses[i]); discoNodes.add(new DiscoveryNode("#cloud-" + instance.getInstanceId() + "-" + i, addresses[i], - emptyMap(), emptySet(), version.minimumCompatibilityVersion())); + emptyMap(), emptySet(), Version.CURRENT.minimumCompatibilityVersion())); } } catch (Exception e) { logger.warn("failed ot add {}, address {}", e, instance.getInstanceId(), address); diff --git a/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryTests.java b/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryTests.java index 319222caa7e..edb062d9e30 100644 --- a/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryTests.java +++ b/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryTests.java @@ -76,10 +76,7 @@ public class Ec2DiscoveryTests extends ESTestCase { protected List buildDynamicNodes(Settings nodeSettings, int nodes, List> tagsList) { AwsEc2Service awsEc2Service = new AwsEc2ServiceMock(nodeSettings, nodes, tagsList); - - AwsEc2UnicastHostsProvider provider = new AwsEc2UnicastHostsProvider(nodeSettings, transportService, - awsEc2Service, Version.CURRENT); - + AwsEc2UnicastHostsProvider provider = new AwsEc2UnicastHostsProvider(nodeSettings, transportService, awsEc2Service); List discoveryNodes = provider.buildDynamicNodes(); logger.debug("--> nodes found: {}", discoveryNodes); return discoveryNodes; @@ -231,14 +228,14 @@ public class Ec2DiscoveryTests extends ESTestCase { abstract class DummyEc2HostProvider extends AwsEc2UnicastHostsProvider { public int fetchCount = 0; - public DummyEc2HostProvider(Settings settings, TransportService transportService, AwsEc2Service service, Version version) { - super(settings, transportService, service, version); + public DummyEc2HostProvider(Settings settings, TransportService transportService, AwsEc2Service service) { + super(settings, transportService, service); } } public void testGetNodeListEmptyCache() throws Exception { AwsEc2Service awsEc2Service = new AwsEc2ServiceMock(Settings.EMPTY, 1, null); - DummyEc2HostProvider provider = new DummyEc2HostProvider(Settings.EMPTY, transportService, awsEc2Service, Version.CURRENT) { + DummyEc2HostProvider provider = new DummyEc2HostProvider(Settings.EMPTY, transportService, awsEc2Service) { @Override protected List fetchDynamicNodes() { fetchCount++; @@ -255,7 +252,7 @@ public class Ec2DiscoveryTests extends ESTestCase { Settings.Builder builder = Settings.builder() .put(DISCOVERY_EC2.NODE_CACHE_TIME_SETTING.getKey(), "500ms"); AwsEc2Service awsEc2Service = new AwsEc2ServiceMock(Settings.EMPTY, 1, null); - DummyEc2HostProvider provider = new DummyEc2HostProvider(builder.build(), transportService, awsEc2Service, Version.CURRENT) { + DummyEc2HostProvider provider = new DummyEc2HostProvider(builder.build(), transportService, awsEc2Service) { @Override protected List fetchDynamicNodes() { fetchCount++; diff --git a/plugins/discovery-gce/src/main/java/org/elasticsearch/discovery/gce/GceUnicastHostsProvider.java b/plugins/discovery-gce/src/main/java/org/elasticsearch/discovery/gce/GceUnicastHostsProvider.java index 29332f61678..c9dd2263245 100644 --- a/plugins/discovery-gce/src/main/java/org/elasticsearch/discovery/gce/GceUnicastHostsProvider.java +++ b/plugins/discovery-gce/src/main/java/org/elasticsearch/discovery/gce/GceUnicastHostsProvider.java @@ -68,7 +68,6 @@ public class GceUnicastHostsProvider extends AbstractComponent implements Unicas private TransportService transportService; private NetworkService networkService; - private final Version version; private final String project; private final List zones; private final List tags; @@ -80,13 +79,11 @@ public class GceUnicastHostsProvider extends AbstractComponent implements Unicas @Inject public GceUnicastHostsProvider(Settings settings, GceComputeService gceComputeService, TransportService transportService, - NetworkService networkService, - Version version) { + NetworkService networkService) { super(settings); this.gceComputeService = gceComputeService; this.transportService = transportService; this.networkService = networkService; - this.version = version; this.refreshInterval = GceComputeService.REFRESH_SETTING.get(settings); this.project = GceComputeService.PROJECT_SETTING.get(settings); @@ -244,7 +241,7 @@ public class GceUnicastHostsProvider extends AbstractComponent implements Unicas logger.trace("adding {}, type {}, address {}, transport_address {}, status {}", name, type, ip_private, transportAddress, status); cachedDiscoNodes.add(new DiscoveryNode("#cloud-" + name + "-" + 0, transportAddress, - emptyMap(), emptySet(), version.minimumCompatibilityVersion())); + emptyMap(), emptySet(), Version.CURRENT.minimumCompatibilityVersion())); } } } catch (Exception e) { diff --git a/plugins/discovery-gce/src/test/java/org/elasticsearch/discovery/gce/GceDiscoveryTests.java b/plugins/discovery-gce/src/test/java/org/elasticsearch/discovery/gce/GceDiscoveryTests.java index e1041360b1f..07b2ef774b4 100644 --- a/plugins/discovery-gce/src/test/java/org/elasticsearch/discovery/gce/GceDiscoveryTests.java +++ b/plugins/discovery-gce/src/test/java/org/elasticsearch/discovery/gce/GceDiscoveryTests.java @@ -78,7 +78,7 @@ public class GceDiscoveryTests extends ESTestCase { @AfterClass public static void stopThreadPool() { - if (threadPool !=null) { + if (threadPool != null) { threadPool.shutdownNow(); threadPool = null; } @@ -111,8 +111,8 @@ public class GceDiscoveryTests extends ESTestCase { } protected List buildDynamicNodes(GceComputeService gceComputeService, Settings nodeSettings) { - GceUnicastHostsProvider provider = new GceUnicastHostsProvider(nodeSettings, gceComputeService, - transportService, new NetworkService(Settings.EMPTY), Version.CURRENT); + GceUnicastHostsProvider provider = new GceUnicastHostsProvider(nodeSettings, gceComputeService, transportService, + new NetworkService(Settings.EMPTY)); List discoveryNodes = provider.buildDynamicNodes(); logger.info("--> nodes found: {}", discoveryNodes); diff --git a/plugins/lang-javascript/src/main/java/org/elasticsearch/script/javascript/JavaScriptScriptEngineService.java b/plugins/lang-javascript/src/main/java/org/elasticsearch/script/javascript/JavaScriptScriptEngineService.java index 3ef030bdeb0..3a556ce4429 100644 --- a/plugins/lang-javascript/src/main/java/org/elasticsearch/script/javascript/JavaScriptScriptEngineService.java +++ b/plugins/lang-javascript/src/main/java/org/elasticsearch/script/javascript/JavaScriptScriptEngineService.java @@ -148,11 +148,6 @@ public class JavaScriptScriptEngineService extends AbstractComponent implements @Override public void close() { - - } - - @Override - public void scriptRemoved(@Nullable CompiledScript compiledScript) { // Nothing to do here } diff --git a/plugins/lang-python/src/main/java/org/elasticsearch/script/python/PythonScriptEngineService.java b/plugins/lang-python/src/main/java/org/elasticsearch/script/python/PythonScriptEngineService.java index 26bf1bed6fc..b642b7b0a73 100644 --- a/plugins/lang-python/src/main/java/org/elasticsearch/script/python/PythonScriptEngineService.java +++ b/plugins/lang-python/src/main/java/org/elasticsearch/script/python/PythonScriptEngineService.java @@ -142,11 +142,6 @@ public class PythonScriptEngineService extends AbstractComponent implements Scri interp.cleanup(); } - @Override - public void scriptRemoved(@Nullable CompiledScript compiledScript) { - // Nothing to do - } - public class PythonExecutableScript implements ExecutableScript { private final PyCode code; diff --git a/plugins/repository-azure/src/test/java/org/elasticsearch/repositories/azure/AzureRepositoryF.java b/plugins/repository-azure/src/test/java/org/elasticsearch/repositories/azure/AzureRepositoryF.java index 4150fe54979..bfa06219127 100644 --- a/plugins/repository-azure/src/test/java/org/elasticsearch/repositories/azure/AzureRepositoryF.java +++ b/plugins/repository-azure/src/test/java/org/elasticsearch/repositories/azure/AzureRepositoryF.java @@ -21,7 +21,6 @@ package org.elasticsearch.repositories.azure; import org.apache.lucene.util.IOUtils; import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.Version; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.node.MockNode; import org.elasticsearch.node.Node; @@ -111,7 +110,7 @@ public class AzureRepositoryF { // settings.put("cloud.azure.storage.my_account2.key", "account_key_secondary"); final CountDownLatch latch = new CountDownLatch(1); - final Node node = new MockNode(settings.build(), Version.CURRENT, Collections.singletonList(AzureRepositoryPlugin.class)); + final Node node = new MockNode(settings.build(), Collections.singletonList(AzureRepositoryPlugin.class)); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { diff --git a/test/framework/src/main/java/org/elasticsearch/common/util/MockBigArrays.java b/test/framework/src/main/java/org/elasticsearch/common/util/MockBigArrays.java index 26e021bf031..613445c2271 100644 --- a/test/framework/src/main/java/org/elasticsearch/common/util/MockBigArrays.java +++ b/test/framework/src/main/java/org/elasticsearch/common/util/MockBigArrays.java @@ -74,7 +74,6 @@ public class MockBigArrays extends BigArrays { private final PageCacheRecycler recycler; private final CircuitBreakerService breakerService; - @Inject public MockBigArrays(Settings settings, CircuitBreakerService breakerService) { this(new MockPageCacheRecycler(settings), breakerService, false); } diff --git a/test/framework/src/main/java/org/elasticsearch/node/MockNode.java b/test/framework/src/main/java/org/elasticsearch/node/MockNode.java index 57dcc08f4fe..33077d5ffbd 100644 --- a/test/framework/src/main/java/org/elasticsearch/node/MockNode.java +++ b/test/framework/src/main/java/org/elasticsearch/node/MockNode.java @@ -19,8 +19,10 @@ package org.elasticsearch.node; -import org.elasticsearch.Version; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.common.util.MockBigArrays; +import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.node.internal.InternalSettingsPreparer; import org.elasticsearch.plugins.Plugin; @@ -35,21 +37,25 @@ import java.util.Collection; */ public class MockNode extends Node { - // these are kept here so a copy of this MockNode can be created, since Node does not store them - private Version version; + private final boolean mockBigArrays; private Collection> plugins; - public MockNode(Settings settings, Version version, Collection> classpathPlugins) { - super(InternalSettingsPreparer.prepareEnvironment(settings, null), version, classpathPlugins); - this.version = version; + public MockNode(Settings settings, Collection> classpathPlugins) { + super(InternalSettingsPreparer.prepareEnvironment(settings, null), classpathPlugins); this.plugins = classpathPlugins; + this.mockBigArrays = classpathPlugins.contains(NodeMocksPlugin.class); // if this plugin is present we mock bigarrays :) } public Collection> getPlugins() { return plugins; } - public Version getVersion() { - return version; + @Override + protected BigArrays createBigArrays(Settings settings, CircuitBreakerService circuitBreakerService) { + if (mockBigArrays) { + return new MockBigArrays(settings, circuitBreakerService); + } else { + return super.createBigArrays(settings, circuitBreakerService); + } } } diff --git a/test/framework/src/main/java/org/elasticsearch/node/NodeMocksPlugin.java b/test/framework/src/main/java/org/elasticsearch/node/NodeMocksPlugin.java index a121ad46bcc..2ca1ac7804d 100644 --- a/test/framework/src/main/java/org/elasticsearch/node/NodeMocksPlugin.java +++ b/test/framework/src/main/java/org/elasticsearch/node/NodeMocksPlugin.java @@ -18,12 +18,7 @@ */ package org.elasticsearch.node; -import org.elasticsearch.common.util.MockBigArrays; import org.elasticsearch.plugins.Plugin; -public class NodeMocksPlugin extends Plugin { - - public void onModule(NodeModule module) { - module.bigArraysImpl = MockBigArrays.class; - } +public class NodeMocksPlugin extends Plugin { // just a marker plugin for MockNode to mock out BigArrays } diff --git a/test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java b/test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java index 64107f56fa7..61a0cf6c236 100644 --- a/test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java +++ b/test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java @@ -110,10 +110,6 @@ public class MockScriptEngine implements ScriptEngineService { }; } - @Override - public void scriptRemoved(@Nullable CompiledScript script) { - } - @Override public void close() throws IOException { } diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java index 62a843cee35..ea2154b355e 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java @@ -53,7 +53,6 @@ import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.Injector; import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.inject.ModulesBuilder; -import org.elasticsearch.common.inject.multibindings.Multibinder; import org.elasticsearch.common.inject.util.Providers; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput; @@ -70,7 +69,6 @@ import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.env.Environment; -import org.elasticsearch.env.EnvironmentModule; import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.analysis.AnalysisRegistry; @@ -95,17 +93,10 @@ import org.elasticsearch.indices.mapper.MapperRegistry; import org.elasticsearch.indices.query.IndicesQueriesRegistry; import org.elasticsearch.node.internal.InternalSettingsPreparer; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.plugins.PluginsModule; import org.elasticsearch.plugins.PluginsService; -import org.elasticsearch.script.MockScriptEngine; import org.elasticsearch.script.Script.ScriptParseException; -import org.elasticsearch.script.ScriptContext; -import org.elasticsearch.script.ScriptContextRegistry; -import org.elasticsearch.script.ScriptEngineRegistry; -import org.elasticsearch.script.ScriptEngineService; import org.elasticsearch.script.ScriptModule; import org.elasticsearch.script.ScriptService; -import org.elasticsearch.script.ScriptSettings; import org.elasticsearch.search.SearchModule; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.threadpool.ThreadPool; @@ -120,14 +111,11 @@ import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Set; import java.util.concurrent.ExecutionException; import static org.hamcrest.Matchers.containsString; @@ -900,9 +888,12 @@ public abstract class AbstractQueryTestCase> for (Module pluginModule : pluginsService.nodeModules()) { modulesBuilder.add(pluginModule); } - modulesBuilder.add(new PluginsModule(pluginsService)); modulesBuilder.add( - new EnvironmentModule(new Environment(settings), threadPool), + (b) -> { + b.bind(PluginsService.class).toInstance(pluginsService); + b.bind(Environment.class).toInstance(new Environment(settings)); + b.bind(ThreadPool.class).toInstance(threadPool); + }, settingsModule, new IndicesModule(namedWriteableRegistry) { @Override public void configure() { diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java index 4cf058a6a5d..8f06e75b038 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java @@ -19,7 +19,6 @@ package org.elasticsearch.test; import org.apache.lucene.util.IOUtils; -import org.elasticsearch.Version; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; import org.elasticsearch.action.admin.indices.get.GetIndexResponse; @@ -147,10 +146,6 @@ public abstract class ESSingleNodeTestCase extends ESTestCase { return false; } - /** The version of elasticsearch the node should act like. */ - protected Version getVersion() { - return Version.CURRENT; - } /** The plugin classes that should be added to the node. */ protected Collection> getPlugins() { @@ -187,7 +182,7 @@ public abstract class ESSingleNodeTestCase extends ESTestCase { .put(Node.NODE_DATA_SETTING.getKey(), true) .put(nodeSettings()) // allow test cases to provide their own settings or override these .build(); - Node build = new MockNode(settings, getVersion(), getPlugins()); + Node build = new MockNode(settings, getPlugins()); build.start(); assertThat(DiscoveryNode.isLocalNode(build.settings()), is(true)); return build; diff --git a/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java b/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java index bb33ad17dde..025740dbe36 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java +++ b/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java @@ -614,7 +614,7 @@ public final class InternalTestCluster extends TestCluster { .put("node.name", name) .put(DiscoveryNodeService.NODE_ID_SEED_SETTING.getKey(), seed) .build(); - MockNode node = new MockNode(finalSettings, version, plugins); + MockNode node = new MockNode(finalSettings, plugins); return new NodeAndClient(name, node); } @@ -888,8 +888,7 @@ public final class InternalTestCluster extends TestCluster { final long newIdSeed = DiscoveryNodeService.NODE_ID_SEED_SETTING.get(node.settings()) + 1; // use a new seed to make sure we have new node id Settings finalSettings = Settings.builder().put(node.settings()).put(newSettings).put(DiscoveryNodeService.NODE_ID_SEED_SETTING.getKey(), newIdSeed).build(); Collection> plugins = node.getPlugins(); - Version version = node.getVersion(); - node = new MockNode(finalSettings, version, plugins); + node = new MockNode(finalSettings, plugins); node.start(); } @@ -903,9 +902,12 @@ public final class InternalTestCluster extends TestCluster { @Override public void close() throws IOException { - resetClient(); - closed.set(true); - closeNode(); + try { + resetClient(); + } finally { + closed.set(true); + closeNode(); + } } } diff --git a/test/framework/src/main/java/org/elasticsearch/test/NodeConfigurationSource.java b/test/framework/src/main/java/org/elasticsearch/test/NodeConfigurationSource.java index c54a00b174d..e04e840e525 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/NodeConfigurationSource.java +++ b/test/framework/src/main/java/org/elasticsearch/test/NodeConfigurationSource.java @@ -19,18 +19,10 @@ package org.elasticsearch.test; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.index.MockEngineFactoryPlugin; -import org.elasticsearch.node.NodeMocksPlugin; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.search.MockSearchService; -import org.elasticsearch.test.store.MockFSIndexStore; -import org.elasticsearch.test.transport.AssertingLocalTransport; -import org.elasticsearch.test.transport.MockTransportService; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.List; public abstract class NodeConfigurationSource { diff --git a/test/framework/src/main/java/org/elasticsearch/test/transport/AssertingLocalTransport.java b/test/framework/src/main/java/org/elasticsearch/test/transport/AssertingLocalTransport.java index 0dd8edb75f8..0142acf8c17 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/transport/AssertingLocalTransport.java +++ b/test/framework/src/main/java/org/elasticsearch/test/transport/AssertingLocalTransport.java @@ -27,7 +27,6 @@ import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.settings.SettingsModule; import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.test.ESIntegTestCase; @@ -75,8 +74,8 @@ public class AssertingLocalTransport extends LocalTransport { @Inject public AssertingLocalTransport(Settings settings, CircuitBreakerService circuitBreakerService, ThreadPool threadPool, - Version version, NamedWriteableRegistry namedWriteableRegistry) { - super(settings, threadPool, version, namedWriteableRegistry, circuitBreakerService); + NamedWriteableRegistry namedWriteableRegistry) { + super(settings, threadPool, namedWriteableRegistry, circuitBreakerService); final long seed = ESIntegTestCase.INDEX_TEST_SEED_SETTING.get(settings); random = new Random(seed); minVersion = ASSERTING_TRANSPORT_MIN_VERSION_KEY.get(settings); diff --git a/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransportService.java b/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransportService.java index 110850e9a0f..7688e2842e6 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransportService.java +++ b/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransportService.java @@ -96,17 +96,26 @@ public class MockTransportService extends TransportService { public static MockTransportService local(Settings settings, Version version, ThreadPool threadPool) { NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry(); - Transport transport = new LocalTransport(settings, threadPool, version, namedWriteableRegistry, new NoneCircuitBreakerService()); + Transport transport = new LocalTransport(settings, threadPool, namedWriteableRegistry, new NoneCircuitBreakerService()) { + @Override + protected Version getVersion() { + return version; + } + }; return new MockTransportService(settings, transport, threadPool); } public static MockTransportService nettyFromThreadPool( Settings settings, - Version version, - ThreadPool threadPool) { + ThreadPool threadPool, final Version version) { NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry(); Transport transport = new NettyTransport(settings, threadPool, new NetworkService(settings), BigArrays.NON_RECYCLING_INSTANCE, - version, namedWriteableRegistry, new NoneCircuitBreakerService()); + namedWriteableRegistry, new NoneCircuitBreakerService()) { + @Override + protected Version getCurrentVersion() { + return version; + } + }; return new MockTransportService(Settings.EMPTY, transport, threadPool); }