From d6c2b4f7c578a6013dfd57806e011030d1647482 Mon Sep 17 00:00:00 2001 From: Boaz Leskes Date: Tue, 15 Nov 2016 13:42:26 +0000 Subject: [PATCH 01/25] Adapt InternalTestCluster to auto adjust `minimum_master_nodes` (#21458) #20960 removed `LocalDiscovery` and we now use `ZenDiscovery` in all our tests. To keep cluster forming fast, we are using a `MockZenPing` implementation which uses static maps to return instant results making master election fast. Currently, we don't set `minimum_master_nodes` causing the occasional split brain when starting multiple nodes concurrently and their pinging is so fast that it misses the fact that one of the node has elected it self master. To solve this, `InternalTestCluster` is modified to behave like a true cluster and manage and set `minimum_master_nodes` correctly with every change to the number of nodes. Tests that want to manage the settings themselves can opt out using a new `autoMinMasterNodes` parameter to the `ClusterScope` annotation. Having `min_master_nodes` set means the started node may need to wait for other nodes to be started as well. To combat this, we set `discovery.initial_state_timeout` to `0` and wait for the cluster to form once all node have been started. Also, because a node may wait and ping while other nodes are started, `MockZenPing` is adapted to wait rather than busy-ping. --- .../discovery/zen/UnicastZenPing.java | 48 +- .../discovery/zen/ZenDiscovery.java | 4 +- .../elasticsearch/discovery/zen/ZenPing.java | 20 +- .../java/org/elasticsearch/node/Node.java | 7 +- .../admin/indices/exists/IndicesExistsIT.java | 3 +- .../master/IndexingMasterFailoverIT.java | 2 +- .../cluster/MinimumMasterNodesIT.java | 15 +- .../elasticsearch/cluster/NoMasterNodeIT.java | 2 +- .../ack/AckClusterUpdateSettingsIT.java | 5 +- .../org/elasticsearch/cluster/ack/AckIT.java | 5 +- .../allocation/AwarenessAllocationIT.java | 2 - .../cluster/service/ClusterServiceIT.java | 156 ----- .../cluster/service/ClusterServiceTests.java | 44 ++ .../DiscoveryWithServiceDisruptionsIT.java | 2 +- .../discovery/ZenUnicastDiscoveryIT.java | 2 +- .../gateway/QuorumGatewayIT.java | 6 +- .../gateway/RecoverAfterNodesIT.java | 2 +- .../gateway/RecoveryFromGatewayIT.java | 88 ++- .../indices/recovery/IndexRecoveryIT.java | 6 +- .../indices/state/RareClusterStateIT.java | 6 +- .../recovery/FullRollingRestartIT.java | 14 +- .../elasticsearch/recovery/RelocationIT.java | 26 +- .../java/org/elasticsearch/tribe/TribeIT.java | 28 +- .../classic/AzureMinimumMasterNodesTests.java | 3 +- .../ec2/Ec2DiscoveryUpdateSettingsTests.java | 2 +- .../elasticsearch/test/ESIntegTestCase.java | 29 +- .../org/elasticsearch/test/ESTestCase.java | 8 +- .../test/InternalTestCluster.java | 555 +++++++++++------- .../test/discovery/MockZenPing.java | 54 +- .../hamcrest/ElasticsearchAssertions.java | 2 +- .../test/test/InternalTestClusterTests.java | 162 ++++- 31 files changed, 749 insertions(+), 559 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/discovery/zen/UnicastZenPing.java b/core/src/main/java/org/elasticsearch/discovery/zen/UnicastZenPing.java index f6870cc05b6..7794c58ddd3 100644 --- a/core/src/main/java/org/elasticsearch/discovery/zen/UnicastZenPing.java +++ b/core/src/main/java/org/elasticsearch/discovery/zen/UnicastZenPing.java @@ -19,30 +19,9 @@ package org.elasticsearch.discovery.zen; -import java.io.Closeable; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; - import com.carrotsearch.hppc.cursors.ObjectCursor; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.util.Supplier; -import org.apache.lucene.util.IOUtils; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.Version; import org.elasticsearch.cluster.ClusterName; @@ -53,6 +32,8 @@ import org.elasticsearch.common.UUIDs; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.lease.Releasable; +import org.elasticsearch.common.lease.Releasables; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; @@ -75,6 +56,25 @@ import org.elasticsearch.transport.TransportResponse; import org.elasticsearch.transport.TransportResponseHandler; import org.elasticsearch.transport.TransportService; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; + import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static java.util.Collections.emptySet; @@ -186,9 +186,9 @@ public class UnicastZenPing extends AbstractComponent implements ZenPing { } @Override - public void close() throws IOException { + public void close() { ThreadPool.terminate(unicastConnectExecutor, 0, TimeUnit.SECONDS); - IOUtils.close(receivedResponses.values()); + Releasables.close(receivedResponses.values()); closed = true; } @@ -272,7 +272,7 @@ public class UnicastZenPing extends AbstractComponent implements ZenPing { } } - class SendPingsHandler implements Closeable { + class SendPingsHandler implements Releasable { private final int id; private final Set nodeToDisconnect = ConcurrentCollections.newConcurrentSet(); private final PingCollection pingCollection; diff --git a/core/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java b/core/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java index f9a16243e00..272a75f4e7a 100644 --- a/core/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java +++ b/core/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java @@ -47,6 +47,7 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.internal.Nullable; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.lease.Releasables; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; @@ -240,6 +241,7 @@ public class ZenDiscovery extends AbstractLifecycleComponent implements Discover joinThreadControl.stop(); masterFD.stop("zen disco stop"); nodesFD.stop(); + Releasables.close(zenPing); // stop any ongoing pinging DiscoveryNodes nodes = nodes(); if (sendLeaveRequest) { if (nodes.getMasterNode() == null) { @@ -269,7 +271,7 @@ public class ZenDiscovery extends AbstractLifecycleComponent implements Discover @Override protected void doClose() throws IOException { - IOUtils.close(masterFD, nodesFD, zenPing); + IOUtils.close(masterFD, nodesFD); } @Override diff --git a/core/src/main/java/org/elasticsearch/discovery/zen/ZenPing.java b/core/src/main/java/org/elasticsearch/discovery/zen/ZenPing.java index cb2c8cb5019..75ea701dc99 100644 --- a/core/src/main/java/org/elasticsearch/discovery/zen/ZenPing.java +++ b/core/src/main/java/org/elasticsearch/discovery/zen/ZenPing.java @@ -19,7 +19,15 @@ package org.elasticsearch.discovery.zen; -import java.io.Closeable; +import org.elasticsearch.cluster.ClusterName; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.node.DiscoveryNode; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Streamable; +import org.elasticsearch.common.lease.Releasable; +import org.elasticsearch.common.unit.TimeValue; + import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -28,17 +36,9 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; -import org.elasticsearch.cluster.ClusterName; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.node.DiscoveryNode; -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.io.stream.Streamable; -import org.elasticsearch.common.unit.TimeValue; - import static org.elasticsearch.gateway.GatewayService.STATE_NOT_RECOVERED_BLOCK; -public interface ZenPing extends Closeable { +public interface ZenPing extends Releasable { void start(PingContextProvider contextProvider); diff --git a/core/src/main/java/org/elasticsearch/node/Node.java b/core/src/main/java/org/elasticsearch/node/Node.java index 9eb7f9a0376..298d6712ff0 100644 --- a/core/src/main/java/org/elasticsearch/node/Node.java +++ b/core/src/main/java/org/elasticsearch/node/Node.java @@ -75,9 +75,6 @@ import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.discovery.Discovery; import org.elasticsearch.discovery.DiscoveryModule; import org.elasticsearch.discovery.DiscoverySettings; -import org.elasticsearch.discovery.zen.UnicastHostsProvider; -import org.elasticsearch.discovery.zen.UnicastZenPing; -import org.elasticsearch.discovery.zen.ZenPing; import org.elasticsearch.env.Environment; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.gateway.GatewayAllocator; @@ -655,11 +652,13 @@ public class Node implements Closeable { injector.getInstance(SnapshotShardsService.class).stop(); // stop any changes happening as a result of cluster state changes injector.getInstance(IndicesClusterStateService.class).stop(); + // close discovery early to not react to pings anymore. + // This can confuse other nodes and delay things - mostly if we're the master and we're running tests. + injector.getInstance(Discovery.class).stop(); // we close indices first, so operations won't be allowed on it injector.getInstance(IndicesTTLService.class).stop(); injector.getInstance(RoutingService.class).stop(); injector.getInstance(ClusterService.class).stop(); - injector.getInstance(Discovery.class).stop(); injector.getInstance(NodeConnectionsService.class).stop(); injector.getInstance(MonitorService.class).stop(); injector.getInstance(GatewayService.class).stop(); diff --git a/core/src/test/java/org/elasticsearch/action/admin/indices/exists/IndicesExistsIT.java b/core/src/test/java/org/elasticsearch/action/admin/indices/exists/IndicesExistsIT.java index e289d90c7a8..b5ef7a642ad 100644 --- a/core/src/test/java/org/elasticsearch/action/admin/indices/exists/IndicesExistsIT.java +++ b/core/src/test/java/org/elasticsearch/action/admin/indices/exists/IndicesExistsIT.java @@ -31,7 +31,8 @@ import java.io.IOException; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows; -@ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, numClientNodes = 0, transportClientRatio = 0.0) +@ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, numClientNodes = 0, transportClientRatio = 0.0, + autoMinMasterNodes = false) public class IndicesExistsIT extends ESIntegTestCase { public void testIndexExistsWithBlocksInPlace() throws IOException { diff --git a/core/src/test/java/org/elasticsearch/action/support/master/IndexingMasterFailoverIT.java b/core/src/test/java/org/elasticsearch/action/support/master/IndexingMasterFailoverIT.java index 96ba5729cb8..7c764ed1724 100644 --- a/core/src/test/java/org/elasticsearch/action/support/master/IndexingMasterFailoverIT.java +++ b/core/src/test/java/org/elasticsearch/action/support/master/IndexingMasterFailoverIT.java @@ -43,7 +43,7 @@ import java.util.concurrent.CyclicBarrier; import static org.hamcrest.Matchers.equalTo; -@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0) +@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, autoMinMasterNodes = false) public class IndexingMasterFailoverIT extends ESIntegTestCase { @Override diff --git a/core/src/test/java/org/elasticsearch/cluster/MinimumMasterNodesIT.java b/core/src/test/java/org/elasticsearch/cluster/MinimumMasterNodesIT.java index 3e58291d4ad..257b80663a3 100644 --- a/core/src/test/java/org/elasticsearch/cluster/MinimumMasterNodesIT.java +++ b/core/src/test/java/org/elasticsearch/cluster/MinimumMasterNodesIT.java @@ -63,7 +63,7 @@ import static org.hamcrest.Matchers.isOneOf; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; -@ClusterScope(scope = Scope.TEST, numDataNodes = 0) +@ClusterScope(scope = Scope.TEST, numDataNodes = 0, autoMinMasterNodes = false) @TestLogging("_root:DEBUG,org.elasticsearch.cluster.service:TRACE,org.elasticsearch.discovery.zen:TRACE") public class MinimumMasterNodesIT extends ESIntegTestCase { @@ -275,12 +275,14 @@ public class MinimumMasterNodesIT extends ESIntegTestCase { .put("discovery.initial_state_timeout", "500ms") .build(); - logger.info("--> start 2 nodes"); - internalCluster().startNodesAsync(2, settings).get(); + logger.info("--> start first node and wait for it to be a master"); + internalCluster().startNode(settings); + ensureClusterSizeConsistency(); // wait until second node join the cluster - ClusterHealthResponse clusterHealthResponse = client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setWaitForNodes("2").get(); - assertThat(clusterHealthResponse.isTimedOut(), equalTo(false)); + logger.info("--> start second node and wait for it to join"); + internalCluster().startNode(settings); + ensureClusterSizeConsistency(); logger.info("--> setting minimum master node to 2"); setMinimumMasterNodes(2); @@ -298,8 +300,7 @@ public class MinimumMasterNodesIT extends ESIntegTestCase { logger.info("--> bringing another node up"); internalCluster().startNode(Settings.builder().put(settings).put(ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey(), 2).build()); - clusterHealthResponse = client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setWaitForNodes("2").get(); - assertThat(clusterHealthResponse.isTimedOut(), equalTo(false)); + ensureClusterSizeConsistency(); } private void assertNoMasterBlockOnAllNodes() throws InterruptedException { diff --git a/core/src/test/java/org/elasticsearch/cluster/NoMasterNodeIT.java b/core/src/test/java/org/elasticsearch/cluster/NoMasterNodeIT.java index f73043ce4e4..0be4f7c4e51 100644 --- a/core/src/test/java/org/elasticsearch/cluster/NoMasterNodeIT.java +++ b/core/src/test/java/org/elasticsearch/cluster/NoMasterNodeIT.java @@ -49,7 +49,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.lessThan; -@ClusterScope(scope = Scope.TEST, numDataNodes = 0) +@ClusterScope(scope = Scope.TEST, numDataNodes = 0, autoMinMasterNodes = false) public class NoMasterNodeIT extends ESIntegTestCase { @Override diff --git a/core/src/test/java/org/elasticsearch/cluster/ack/AckClusterUpdateSettingsIT.java b/core/src/test/java/org/elasticsearch/cluster/ack/AckClusterUpdateSettingsIT.java index f47134a45b8..ab3f82fff75 100644 --- a/core/src/test/java/org/elasticsearch/cluster/ack/AckClusterUpdateSettingsIT.java +++ b/core/src/test/java/org/elasticsearch/cluster/ack/AckClusterUpdateSettingsIT.java @@ -69,7 +69,10 @@ public class AckClusterUpdateSettingsIT extends ESIntegTestCase { private void removePublishTimeout() { //to test that the acknowledgement mechanism is working we better disable the wait for publish //otherwise the operation is most likely acknowledged even if it doesn't support ack - assertAcked(client().admin().cluster().prepareUpdateSettings().setTransientSettings(Settings.builder().put(DiscoverySettings.PUBLISH_TIMEOUT_SETTING.getKey(), "0"))); + assertAcked(client().admin().cluster().prepareUpdateSettings().setTransientSettings(Settings.builder() + .put(DiscoverySettings.PUBLISH_TIMEOUT_SETTING.getKey(), "0") + .put(DiscoverySettings.COMMIT_TIMEOUT_SETTING.getKey(), "30s") + )); } public void testClusterUpdateSettingsAcknowledgement() { diff --git a/core/src/test/java/org/elasticsearch/cluster/ack/AckIT.java b/core/src/test/java/org/elasticsearch/cluster/ack/AckIT.java index 2ea4f755156..f51a4f11ae1 100644 --- a/core/src/test/java/org/elasticsearch/cluster/ack/AckIT.java +++ b/core/src/test/java/org/elasticsearch/cluster/ack/AckIT.java @@ -36,7 +36,6 @@ import org.elasticsearch.cluster.routing.RoutingNode; import org.elasticsearch.cluster.routing.ShardRouting; import org.elasticsearch.cluster.routing.ShardRoutingState; import org.elasticsearch.cluster.routing.allocation.command.MoveAllocationCommand; -import org.elasticsearch.common.collect.Iterators; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.discovery.DiscoverySettings; import org.elasticsearch.index.Index; @@ -61,7 +60,9 @@ public class AckIT extends ESIntegTestCase { //to test that the acknowledgement mechanism is working we better disable the wait for publish //otherwise the operation is most likely acknowledged even if it doesn't support ack return Settings.builder().put(super.nodeSettings(nodeOrdinal)) - .put(DiscoverySettings.PUBLISH_TIMEOUT_SETTING.getKey(), 0).build(); + .put(DiscoverySettings.COMMIT_TIMEOUT_SETTING.getKey(), "30s") // explicitly set so it won't default to publish timeout + .put(DiscoverySettings.PUBLISH_TIMEOUT_SETTING.getKey(), "0s") // don't wait post commit to check acking + .build(); } public void testUpdateSettingsAcknowledgement() { diff --git a/core/src/test/java/org/elasticsearch/cluster/allocation/AwarenessAllocationIT.java b/core/src/test/java/org/elasticsearch/cluster/allocation/AwarenessAllocationIT.java index d98f9294243..19657b05480 100644 --- a/core/src/test/java/org/elasticsearch/cluster/allocation/AwarenessAllocationIT.java +++ b/core/src/test/java/org/elasticsearch/cluster/allocation/AwarenessAllocationIT.java @@ -30,7 +30,6 @@ import org.elasticsearch.cluster.routing.allocation.decider.AwarenessAllocationD import org.elasticsearch.common.Priority; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.discovery.zen.ElectMasterService; import org.elasticsearch.discovery.zen.ZenDiscovery; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase.ClusterScope; @@ -104,7 +103,6 @@ public class AwarenessAllocationIT extends ESIntegTestCase { Settings commonSettings = Settings.builder() .put(AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_FORCE_GROUP_SETTING.getKey() + "zone.values", "a,b") .put(AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING.getKey(), "zone") - .put(ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey(), 3) .put(ZenDiscovery.JOIN_TIMEOUT_SETTING.getKey(), "10s") .build(); diff --git a/core/src/test/java/org/elasticsearch/cluster/service/ClusterServiceIT.java b/core/src/test/java/org/elasticsearch/cluster/service/ClusterServiceIT.java index 3d345f24dbe..f056eded34b 100644 --- a/core/src/test/java/org/elasticsearch/cluster/service/ClusterServiceIT.java +++ b/core/src/test/java/org/elasticsearch/cluster/service/ClusterServiceIT.java @@ -20,32 +20,20 @@ package org.elasticsearch.cluster.service; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.util.Supplier; -import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.cluster.tasks.PendingClusterTasksResponse; import org.elasticsearch.cluster.AckedClusterStateUpdateTask; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterStateUpdateTask; -import org.elasticsearch.cluster.LocalNodeMasterListener; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.Priority; -import org.elasticsearch.common.component.AbstractLifecycleComponent; -import org.elasticsearch.common.component.LifecycleComponent; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.inject.Singleton; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.discovery.zen.ZenDiscovery; -import org.elasticsearch.plugins.Plugin; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.Scope; import org.elasticsearch.test.junit.annotations.TestLogging; -import org.elasticsearch.threadpool.ThreadPool; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -56,17 +44,10 @@ import java.util.concurrent.atomic.AtomicBoolean; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; @ClusterScope(scope = Scope.TEST, numDataNodes = 0) public class ClusterServiceIT extends ESIntegTestCase { - @Override - protected Collection> nodePlugins() { - return Arrays.asList(TestPlugin.class); - } - public void testAckedUpdateTask() throws Exception { internalCluster().startNode(); ClusterService clusterService = internalCluster().getInstance(ClusterService.class); @@ -482,141 +463,4 @@ public class ClusterServiceIT extends ESIntegTestCase { assertTrue(controlSources.isEmpty()); block2.countDown(); } - - public void testLocalNodeMasterListenerCallbacks() throws Exception { - Settings settings = Settings.builder() - .put("discovery.zen.minimum_master_nodes", 1) - .put(ZenDiscovery.PING_TIMEOUT_SETTING.getKey(), "400ms") - .put("discovery.initial_state_timeout", "500ms") - .build(); - - String node_0 = internalCluster().startNode(settings); - ClusterService clusterService = internalCluster().getInstance(ClusterService.class); - MasterAwareService testService = internalCluster().getInstance(MasterAwareService.class); - - ClusterHealthResponse clusterHealth = client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID) - .setWaitForNodes("1").get(); - assertThat(clusterHealth.isTimedOut(), equalTo(false)); - - // the first node should be a master as the minimum required is 1 - assertThat(clusterService.state().nodes().getMasterNode(), notNullValue()); - assertThat(clusterService.state().nodes().isLocalNodeElectedMaster(), is(true)); - assertThat(testService.master(), is(true)); - String node_1 = internalCluster().startNode(settings); - final ClusterService clusterService1 = internalCluster().getInstance(ClusterService.class, node_1); - MasterAwareService testService1 = internalCluster().getInstance(MasterAwareService.class, node_1); - - clusterHealth = client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setWaitForNodes("2").get(); - assertThat(clusterHealth.isTimedOut(), equalTo(false)); - - // the second node should not be the master as node1 is already the master. - assertThat(clusterService1.state().nodes().isLocalNodeElectedMaster(), is(false)); - assertThat(testService1.master(), is(false)); - - internalCluster().stopCurrentMasterNode(); - clusterHealth = client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setWaitForNodes("1").get(); - assertThat(clusterHealth.isTimedOut(), equalTo(false)); - - // now that node0 is closed, node1 should be elected as master - assertThat(clusterService1.state().nodes().isLocalNodeElectedMaster(), is(true)); - assertThat(testService1.master(), is(true)); - - // start another node and set min_master_node - internalCluster().startNode(Settings.builder().put(settings)); - assertFalse(client().admin().cluster().prepareHealth().setWaitForNodes("2").get().isTimedOut()); - - Settings transientSettings = Settings.builder() - .put("discovery.zen.minimum_master_nodes", 2) - .build(); - client().admin().cluster().prepareUpdateSettings().setTransientSettings(transientSettings).get(); - - // and shutdown the second node - internalCluster().stopRandomNonMasterNode(); - - // there should not be any master as the minimum number of required eligible masters is not met - awaitBusy(() -> clusterService1.state().nodes().getMasterNode() == null && - clusterService1.clusterServiceState().getClusterStateStatus() == ClusterStateStatus.APPLIED); - assertThat(testService1.master(), is(false)); - - // bring the node back up - String node_2 = internalCluster().startNode(Settings.builder().put(settings).put(transientSettings)); - ClusterService clusterService2 = internalCluster().getInstance(ClusterService.class, node_2); - MasterAwareService testService2 = internalCluster().getInstance(MasterAwareService.class, node_2); - - // make sure both nodes see each other otherwise the masternode below could be null if node 2 is master and node 1 did'r receive - // the updated cluster state... - assertThat(internalCluster().client(node_1).admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setLocal(true) - .setWaitForNodes("2").get().isTimedOut(), is(false)); - assertThat(internalCluster().client(node_2).admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setLocal(true) - .setWaitForNodes("2").get().isTimedOut(), is(false)); - - // now that we started node1 again, a new master should be elected - assertThat(clusterService2.state().nodes().getMasterNode(), is(notNullValue())); - if (node_2.equals(clusterService2.state().nodes().getMasterNode().getName())) { - assertThat(testService1.master(), is(false)); - assertThat(testService2.master(), is(true)); - } else { - assertThat(testService1.master(), is(true)); - assertThat(testService2.master(), is(false)); - } - } - - public static class TestPlugin extends Plugin { - - @Override - public Collection> getGuiceServiceClasses() { - List> services = new ArrayList<>(1); - services.add(MasterAwareService.class); - return services; - } - } - - @Singleton - public static class MasterAwareService extends AbstractLifecycleComponent implements LocalNodeMasterListener { - - private final ClusterService clusterService; - private volatile boolean master; - - @Inject - public MasterAwareService(Settings settings, ClusterService clusterService) { - super(settings); - clusterService.add(this); - this.clusterService = clusterService; - logger.info("initialized test service"); - } - - @Override - public void onMaster() { - logger.info("on master [{}]", clusterService.localNode()); - master = true; - } - - @Override - public void offMaster() { - logger.info("off master [{}]", clusterService.localNode()); - master = false; - } - - public boolean master() { - return master; - } - - @Override - protected void doStart() { - } - - @Override - protected void doStop() { - } - - @Override - protected void doClose() { - } - - @Override - public String executorName() { - return ThreadPool.Names.SAME; - } - - } } diff --git a/core/src/test/java/org/elasticsearch/cluster/service/ClusterServiceTests.java b/core/src/test/java/org/elasticsearch/cluster/service/ClusterServiceTests.java index 9fd4fc18514..bede01ed21b 100644 --- a/core/src/test/java/org/elasticsearch/cluster/service/ClusterServiceTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/service/ClusterServiceTests.java @@ -30,6 +30,7 @@ import org.elasticsearch.cluster.ClusterStateTaskConfig; import org.elasticsearch.cluster.ClusterStateTaskExecutor; import org.elasticsearch.cluster.ClusterStateTaskListener; import org.elasticsearch.cluster.ClusterStateUpdateTask; +import org.elasticsearch.cluster.LocalNodeMasterListener; import org.elasticsearch.cluster.NodeConnectionsService; import org.elasticsearch.cluster.block.ClusterBlocks; import org.elasticsearch.cluster.node.DiscoveryNode; @@ -44,6 +45,7 @@ import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.BaseFuture; import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.discovery.Discovery; +import org.elasticsearch.discovery.DiscoverySettings; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.MockLogAppender; import org.elasticsearch.test.junit.annotations.TestLogging; @@ -1098,6 +1100,48 @@ public class ClusterServiceTests extends ESTestCase { timedClusterService.close(); } + public void testLocalNodeMasterListenerCallbacks() throws Exception { + TimedClusterService timedClusterService = createTimedClusterService(false); + + AtomicBoolean isMaster = new AtomicBoolean(); + timedClusterService.add(new LocalNodeMasterListener() { + @Override + public void onMaster() { + isMaster.set(true); + } + + @Override + public void offMaster() { + isMaster.set(false); + } + + @Override + public String executorName() { + return ThreadPool.Names.SAME; + } + }); + + ClusterState state = timedClusterService.state(); + DiscoveryNodes nodes = state.nodes(); + DiscoveryNodes.Builder nodesBuilder = DiscoveryNodes.builder(nodes).masterNodeId(nodes.getLocalNodeId()); + state = ClusterState.builder(state).blocks(ClusterBlocks.EMPTY_CLUSTER_BLOCK).nodes(nodesBuilder).build(); + setState(timedClusterService, state); + assertThat(isMaster.get(), is(true)); + + nodes = state.nodes(); + nodesBuilder = DiscoveryNodes.builder(nodes).masterNodeId(null); + state = ClusterState.builder(state).blocks(ClusterBlocks.builder().addGlobalBlock(DiscoverySettings.NO_MASTER_BLOCK_WRITES)) + .nodes(nodesBuilder).build(); + setState(timedClusterService, state); + assertThat(isMaster.get(), is(false)); + nodesBuilder = DiscoveryNodes.builder(nodes).masterNodeId(nodes.getLocalNodeId()); + state = ClusterState.builder(state).blocks(ClusterBlocks.EMPTY_CLUSTER_BLOCK).nodes(nodesBuilder).build(); + setState(timedClusterService, state); + assertThat(isMaster.get(), is(true)); + + timedClusterService.close(); + } + private static class SimpleTask { private final int id; diff --git a/core/src/test/java/org/elasticsearch/discovery/DiscoveryWithServiceDisruptionsIT.java b/core/src/test/java/org/elasticsearch/discovery/DiscoveryWithServiceDisruptionsIT.java index 22844e05881..1688157c0d1 100644 --- a/core/src/test/java/org/elasticsearch/discovery/DiscoveryWithServiceDisruptionsIT.java +++ b/core/src/test/java/org/elasticsearch/discovery/DiscoveryWithServiceDisruptionsIT.java @@ -122,7 +122,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; -@ClusterScope(scope = Scope.TEST, numDataNodes = 0, transportClientRatio = 0) +@ClusterScope(scope = Scope.TEST, numDataNodes = 0, transportClientRatio = 0, autoMinMasterNodes = false) @TestLogging("_root:DEBUG,org.elasticsearch.cluster.service:TRACE") public class DiscoveryWithServiceDisruptionsIT extends ESIntegTestCase { diff --git a/core/src/test/java/org/elasticsearch/discovery/ZenUnicastDiscoveryIT.java b/core/src/test/java/org/elasticsearch/discovery/ZenUnicastDiscoveryIT.java index 3af2e32eefa..b708ab4c26a 100644 --- a/core/src/test/java/org/elasticsearch/discovery/ZenUnicastDiscoveryIT.java +++ b/core/src/test/java/org/elasticsearch/discovery/ZenUnicastDiscoveryIT.java @@ -34,7 +34,7 @@ import java.util.concurrent.ExecutionException; import static org.hamcrest.Matchers.equalTo; -@ClusterScope(scope = Scope.TEST, numDataNodes = 0) +@ClusterScope(scope = Scope.TEST, numDataNodes = 0, autoMinMasterNodes = false) public class ZenUnicastDiscoveryIT extends ESIntegTestCase { private ClusterDiscoveryConfiguration discoveryConfig; diff --git a/core/src/test/java/org/elasticsearch/gateway/QuorumGatewayIT.java b/core/src/test/java/org/elasticsearch/gateway/QuorumGatewayIT.java index 226b1422b4d..8284388d2ce 100644 --- a/core/src/test/java/org/elasticsearch/gateway/QuorumGatewayIT.java +++ b/core/src/test/java/org/elasticsearch/gateway/QuorumGatewayIT.java @@ -23,7 +23,6 @@ import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.client.Client; import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.discovery.zen.ElectMasterService; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.Scope; @@ -37,7 +36,7 @@ import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; -@ClusterScope(numDataNodes =0, scope= Scope.TEST) +@ClusterScope(numDataNodes = 0, scope = Scope.TEST) public class QuorumGatewayIT extends ESIntegTestCase { @Override protected int numberOfReplicas() { @@ -47,8 +46,7 @@ public class QuorumGatewayIT extends ESIntegTestCase { public void testQuorumRecovery() throws Exception { logger.info("--> starting 3 nodes"); // we are shutting down nodes - make sure we don't have 2 clusters if we test network - internalCluster().startNodesAsync(3, - Settings.builder().put(ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey(), 2).build()).get(); + internalCluster().startNodesAsync(3).get(); createIndex("test"); diff --git a/core/src/test/java/org/elasticsearch/gateway/RecoverAfterNodesIT.java b/core/src/test/java/org/elasticsearch/gateway/RecoverAfterNodesIT.java index 1e35bcdd469..1794aa22728 100644 --- a/core/src/test/java/org/elasticsearch/gateway/RecoverAfterNodesIT.java +++ b/core/src/test/java/org/elasticsearch/gateway/RecoverAfterNodesIT.java @@ -34,7 +34,7 @@ import java.util.Set; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItem; -@ClusterScope(scope = Scope.TEST, numDataNodes = 0) +@ClusterScope(scope = Scope.TEST, numDataNodes = 0, autoMinMasterNodes = false) public class RecoverAfterNodesIT extends ESIntegTestCase { private static final TimeValue BLOCK_WAIT_TIMEOUT = TimeValue.timeValueSeconds(10); diff --git a/core/src/test/java/org/elasticsearch/gateway/RecoveryFromGatewayIT.java b/core/src/test/java/org/elasticsearch/gateway/RecoveryFromGatewayIT.java index 4e1ff3f8678..052bfc00ef2 100644 --- a/core/src/test/java/org/elasticsearch/gateway/RecoveryFromGatewayIT.java +++ b/core/src/test/java/org/elasticsearch/gateway/RecoveryFromGatewayIT.java @@ -23,7 +23,6 @@ import com.carrotsearch.hppc.cursors.ObjectCursor; import org.elasticsearch.action.admin.indices.recovery.RecoveryResponse; import org.elasticsearch.action.admin.indices.stats.IndexStats; import org.elasticsearch.action.admin.indices.stats.ShardStats; -import org.elasticsearch.client.Client; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.node.DiscoveryNode; @@ -44,6 +43,7 @@ import org.elasticsearch.plugins.Plugin; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.Scope; +import org.elasticsearch.test.InternalTestCluster; import org.elasticsearch.test.InternalTestCluster.RestartCallback; import org.elasticsearch.test.store.MockFSDirectoryService; import org.elasticsearch.test.store.MockFSIndexStore; @@ -333,48 +333,43 @@ public class RecoveryFromGatewayIT extends ESIntegTestCase { String metaDataUuid = client().admin().cluster().prepareState().execute().get().getState().getMetaData().clusterUUID(); assertThat(metaDataUuid, not(equalTo("_na_"))); - Map primaryTerms = assertAndCapturePrimaryTerms(null); - logger.info("--> closing first node, and indexing more data to the second node"); - internalCluster().fullRestart(new RestartCallback() { + internalCluster().stopRandomDataNode(); - @Override - public void doAfterNodes(int numNodes, Client client) throws Exception { - if (numNodes == 1) { - logger.info("--> one node is closed - start indexing data into the second one"); - client.prepareIndex("test", "type1", "3").setSource(jsonBuilder().startObject().field("field", "value3").endObject()).execute().actionGet(); - // TODO: remove once refresh doesn't fail immediately if there a master block: - // https://github.com/elastic/elasticsearch/issues/9997 - client.admin().cluster().prepareHealth("test").setWaitForYellowStatus().get(); - client.admin().indices().prepareRefresh().execute().actionGet(); + logger.info("--> one node is closed - start indexing data into the second one"); + client().prepareIndex("test", "type1", "3").setSource(jsonBuilder().startObject().field("field", "value3").endObject()).execute().actionGet(); + // TODO: remove once refresh doesn't fail immediately if there a master block: + // https://github.com/elastic/elasticsearch/issues/9997 + client().admin().cluster().prepareHealth("test").setWaitForYellowStatus().get(); + client().admin().indices().prepareRefresh().execute().actionGet(); - for (int i = 0; i < 10; i++) { - assertHitCount(client.prepareSearch().setSize(0).setQuery(matchAllQuery()).execute().actionGet(), 3); - } + for (int i = 0; i < 10; i++) { + assertHitCount(client().prepareSearch().setSize(0).setQuery(matchAllQuery()).execute().actionGet(), 3); + } - logger.info("--> add some metadata, additional type and template"); - client.admin().indices().preparePutMapping("test").setType("type2") - .setSource(jsonBuilder().startObject().startObject("type2").endObject().endObject()) - .execute().actionGet(); - client.admin().indices().preparePutTemplate("template_1") - .setPatterns(Collections.singletonList("te*")) - .setOrder(0) - .addMapping("type1", XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties") - .startObject("field1").field("type", "text").field("store", true).endObject() - .startObject("field2").field("type", "keyword").field("store", true).endObject() - .endObject().endObject().endObject()) - .execute().actionGet(); - client.admin().indices().prepareAliases().addAlias("test", "test_alias", QueryBuilders.termQuery("field", "value")).execute().actionGet(); - logger.info("--> starting two nodes back, verifying we got the latest version"); - } + logger.info("--> add some metadata, additional type and template"); + client().admin().indices().preparePutMapping("test").setType("type2") + .setSource(jsonBuilder().startObject().startObject("type2").endObject().endObject()) + .execute().actionGet(); + client().admin().indices().preparePutTemplate("template_1") + .setTemplate("te*") + .setOrder(0) + .addMapping("type1", XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties") + .startObject("field1").field("type", "text").field("store", true).endObject() + .startObject("field2").field("type", "keyword").field("store", true).endObject() + .endObject().endObject().endObject()) + .execute().actionGet(); + client().admin().indices().prepareAliases().addAlias("test", "test_alias", QueryBuilders.termQuery("field", "value")).execute().actionGet(); - } + logger.info("--> stopping the second node"); + internalCluster().stopRandomDataNode(); - }); + logger.info("--> starting the two nodes back"); + + internalCluster().startNodesAsync(2, Settings.builder().put("gateway.recover_after_nodes", 2).build()).get(); logger.info("--> running cluster_health (wait for the shards to startup)"); ensureGreen(); - primaryTerms = assertAndCapturePrimaryTerms(primaryTerms); assertThat(client().admin().cluster().prepareState().execute().get().getState().getMetaData().clusterUUID(), equalTo(metaDataUuid)); @@ -502,27 +497,28 @@ public class RecoveryFromGatewayIT extends ESIntegTestCase { public void testRecoveryDifferentNodeOrderStartup() throws Exception { // we need different data paths so we make sure we start the second node fresh - final String node_1 = internalCluster().startNode(Settings.builder().put(Environment.PATH_DATA_SETTING.getKey(), createTempDir()).build()); + final Path pathNode1 = createTempDir(); + final String node_1 = internalCluster().startNode(Settings.builder().put(Environment.PATH_DATA_SETTING.getKey(), pathNode1).build()); client().prepareIndex("test", "type1", "1").setSource("field", "value").execute().actionGet(); - internalCluster().startNode(Settings.builder().put(Environment.PATH_DATA_SETTING.getKey(), createTempDir()).build()); + final Path pathNode2 = createTempDir(); + final String node_2 = internalCluster().startNode(Settings.builder().put(Environment.PATH_DATA_SETTING.getKey(), pathNode2).build()); ensureGreen(); Map primaryTerms = assertAndCapturePrimaryTerms(null); - - internalCluster().fullRestart(new RestartCallback() { - - @Override - public boolean doRestart(String nodeName) { - return !node_1.equals(nodeName); - } - }); - + if (randomBoolean()) { + internalCluster().stopRandomNode(InternalTestCluster.nameFilter(node_1)); + internalCluster().stopRandomNode(InternalTestCluster.nameFilter(node_2)); + } else { + internalCluster().stopRandomNode(InternalTestCluster.nameFilter(node_2)); + internalCluster().stopRandomNode(InternalTestCluster.nameFilter(node_1)); + } + // start the second node again + internalCluster().startNode(Settings.builder().put(Environment.PATH_DATA_SETTING.getKey(), pathNode2).build()); ensureYellow(); primaryTerms = assertAndCapturePrimaryTerms(primaryTerms); - assertThat(client().admin().indices().prepareExists("test").execute().actionGet().isExists(), equalTo(true)); assertHitCount(client().prepareSearch("test").setSize(0).setQuery(QueryBuilders.matchAllQuery()).execute().actionGet(), 1); } diff --git a/core/src/test/java/org/elasticsearch/indices/recovery/IndexRecoveryIT.java b/core/src/test/java/org/elasticsearch/indices/recovery/IndexRecoveryIT.java index dfe9a09fb2a..e0a6111833b 100644 --- a/core/src/test/java/org/elasticsearch/indices/recovery/IndexRecoveryIT.java +++ b/core/src/test/java/org/elasticsearch/indices/recovery/IndexRecoveryIT.java @@ -555,10 +555,8 @@ public class IndexRecoveryIT extends ESIntegTestCase { // start a master node internalCluster().startNode(nodeSettings); - InternalTestCluster.Async blueFuture = internalCluster().startNodeAsync(Settings.builder().put("node.attr.color", "blue").put(nodeSettings).build()); - InternalTestCluster.Async redFuture = internalCluster().startNodeAsync(Settings.builder().put("node.attr.color", "red").put(nodeSettings).build()); - final String blueNodeName = blueFuture.get(); - final String redNodeName = redFuture.get(); + final String blueNodeName = internalCluster().startNode(Settings.builder().put("node.attr.color", "blue").put(nodeSettings).build()); + final String redNodeName = internalCluster().startNode(Settings.builder().put("node.attr.color", "red").put(nodeSettings).build()); ClusterHealthResponse response = client().admin().cluster().prepareHealth().setWaitForNodes(">=3").get(); assertThat(response.isTimedOut(), is(false)); diff --git a/core/src/test/java/org/elasticsearch/indices/state/RareClusterStateIT.java b/core/src/test/java/org/elasticsearch/indices/state/RareClusterStateIT.java index c55fc514332..fe3b569755d 100644 --- a/core/src/test/java/org/elasticsearch/indices/state/RareClusterStateIT.java +++ b/core/src/test/java/org/elasticsearch/indices/state/RareClusterStateIT.java @@ -209,7 +209,10 @@ public class RareClusterStateIT extends ESIntegTestCase { // but the change might not be on the node that performed the indexing // operation yet - Settings settings = Settings.builder().put(DiscoverySettings.PUBLISH_TIMEOUT_SETTING.getKey(), "0ms").build(); + Settings settings = Settings.builder() + .put(DiscoverySettings.COMMIT_TIMEOUT_SETTING.getKey(), "30s") // explicitly set so it won't default to publish timeout + .put(DiscoverySettings.PUBLISH_TIMEOUT_SETTING.getKey(), "0s") // don't wait post commit as we are blocking things by design + .build(); final List nodeNames = internalCluster().startNodesAsync(2, settings).get(); assertFalse(client().admin().cluster().prepareHealth().setWaitForNodes("2").get().isTimedOut()); @@ -327,7 +330,6 @@ public class RareClusterStateIT extends ESIntegTestCase { // time of indexing it final List nodeNames = internalCluster().startNodesAsync(2, Settings.builder() - .put(ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey(), 2) .put(DiscoverySettings.COMMIT_TIMEOUT_SETTING.getKey(), "30s") // explicitly set so it won't default to publish timeout .put(DiscoverySettings.PUBLISH_TIMEOUT_SETTING.getKey(), "0s") // don't wait post commit as we are blocking things by design .build()).get(); diff --git a/core/src/test/java/org/elasticsearch/recovery/FullRollingRestartIT.java b/core/src/test/java/org/elasticsearch/recovery/FullRollingRestartIT.java index 4a61bebd4db..dc388677050 100644 --- a/core/src/test/java/org/elasticsearch/recovery/FullRollingRestartIT.java +++ b/core/src/test/java/org/elasticsearch/recovery/FullRollingRestartIT.java @@ -72,16 +72,15 @@ public class FullRollingRestartIT extends ESIntegTestCase { } logger.info("--> now start adding nodes"); - internalCluster().startNodesAsync(2, settings).get(); + internalCluster().startNode(settings); + internalCluster().startNode(settings); // make sure the cluster state is green, and all has been recovered assertTimeout(client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setTimeout(healthTimeout).setWaitForGreenStatus().setWaitForNoRelocatingShards(true).setWaitForNodes("3")); logger.info("--> add two more nodes"); - internalCluster().startNodesAsync(2, settings).get(); - - // We now have 5 nodes - setMinimumMasterNodes(3); + internalCluster().startNode(settings); + internalCluster().startNode(settings); // make sure the cluster state is green, and all has been recovered assertTimeout(client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setTimeout(healthTimeout).setWaitForGreenStatus().setWaitForNoRelocatingShards(true).setWaitForNodes("5")); @@ -97,9 +96,6 @@ public class FullRollingRestartIT extends ESIntegTestCase { // make sure the cluster state is green, and all has been recovered assertTimeout(client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setTimeout(healthTimeout).setWaitForGreenStatus().setWaitForNoRelocatingShards(true).setWaitForNodes("4")); - // going down to 3 nodes. note that the min_master_node may not be in effect when we shutdown the 4th - // node, but that's OK as it is set to 3 before. - setMinimumMasterNodes(2); internalCluster().stopRandomDataNode(); // make sure the cluster state is green, and all has been recovered assertTimeout(client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setTimeout(healthTimeout).setWaitForGreenStatus().setWaitForNoRelocatingShards(true).setWaitForNodes("3")); @@ -115,8 +111,6 @@ public class FullRollingRestartIT extends ESIntegTestCase { // make sure the cluster state is green, and all has been recovered assertTimeout(client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setTimeout(healthTimeout).setWaitForGreenStatus().setWaitForNoRelocatingShards(true).setWaitForNodes("2")); - // closing the 2nd node - setMinimumMasterNodes(1); internalCluster().stopRandomDataNode(); // make sure the cluster state is yellow, and all has been recovered diff --git a/core/src/test/java/org/elasticsearch/recovery/RelocationIT.java b/core/src/test/java/org/elasticsearch/recovery/RelocationIT.java index 8a59b7460b3..bd474280e4e 100644 --- a/core/src/test/java/org/elasticsearch/recovery/RelocationIT.java +++ b/core/src/test/java/org/elasticsearch/recovery/RelocationIT.java @@ -44,8 +44,8 @@ import org.elasticsearch.index.shard.IndexEventListener; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.index.shard.IndexShardState; import org.elasticsearch.index.shard.ShardId; -import org.elasticsearch.indices.recovery.RecoveryFileChunkRequest; import org.elasticsearch.indices.recovery.PeerRecoveryTargetService; +import org.elasticsearch.indices.recovery.RecoveryFileChunkRequest; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; @@ -53,7 +53,6 @@ import org.elasticsearch.test.BackgroundIndexer; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.Scope; -import org.elasticsearch.test.InternalTestCluster; import org.elasticsearch.test.MockIndexEventListener; import org.elasticsearch.test.junit.annotations.TestLogging; import org.elasticsearch.test.transport.MockTransportService; @@ -77,6 +76,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; @@ -351,7 +351,8 @@ public class RelocationIT extends ESIntegTestCase { client().admin().indices().prepareCreate(indexName) .setSettings(Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1, IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)).get(); - internalCluster().startNodesAsync(2).get(); + internalCluster().startNode(); + internalCluster().startNode(); List requests = new ArrayList<>(); int numDocs = scaledRandomIntBetween(25, 250); @@ -424,14 +425,15 @@ public class RelocationIT extends ESIntegTestCase { public void testIndexAndRelocateConcurrently() throws ExecutionException, InterruptedException { int halfNodes = randomIntBetween(1, 3); - Settings blueSetting = Settings.builder().put("node.attr.color", "blue").build(); - InternalTestCluster.Async> blueFuture = internalCluster().startNodesAsync(halfNodes, blueSetting); - Settings redSetting = Settings.builder().put("node.attr.color", "red").build(); - InternalTestCluster.Async> redFuture = internalCluster().startNodesAsync(halfNodes, redSetting); - blueFuture.get(); - redFuture.get(); - logger.info("blue nodes: {}", blueFuture.get()); - logger.info("red nodes: {}", redFuture.get()); + Settings[] nodeSettings = Stream.concat( + Stream.generate(() -> Settings.builder().put("node.attr.color", "blue").build()).limit(halfNodes), + Stream.generate(() -> Settings.builder().put("node.attr.color", "red").build()).limit(halfNodes) + ).toArray(Settings[]::new); + List nodes = internalCluster().startNodesAsync(nodeSettings).get(); + String[] blueNodes = nodes.subList(0, halfNodes).stream().toArray(String[]::new); + String[] redNodes = nodes.subList(halfNodes, nodes.size()).stream().toArray(String[]::new); + logger.info("blue nodes: {}", (Object)blueNodes); + logger.info("red nodes: {}", (Object)redNodes); ensureStableCluster(halfNodes * 2); assertAcked(prepareCreate("test").setSettings(Settings.builder() @@ -439,7 +441,7 @@ public class RelocationIT extends ESIntegTestCase { .put(indexSettings()) .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, randomInt(halfNodes - 1)) )); - assertAllShardsOnNodes("test", redFuture.get().toArray(new String[2])); + assertAllShardsOnNodes("test", redNodes); int numDocs = randomIntBetween(100, 150); ArrayList ids = new ArrayList<>(); logger.info(" --> indexing [{}] docs", numDocs); diff --git a/core/src/test/java/org/elasticsearch/tribe/TribeIT.java b/core/src/test/java/org/elasticsearch/tribe/TribeIT.java index 6121b2c0c86..cf4fe03893f 100644 --- a/core/src/test/java/org/elasticsearch/tribe/TribeIT.java +++ b/core/src/test/java/org/elasticsearch/tribe/TribeIT.java @@ -19,18 +19,6 @@ package org.elasticsearch.tribe; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.support.DestructiveOperations; import org.elasticsearch.client.Client; @@ -58,6 +46,18 @@ import org.junit.After; import org.junit.AfterClass; import org.junit.Before; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + import static java.util.stream.Collectors.toSet; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; @@ -121,13 +121,13 @@ public class TribeIT extends ESIntegTestCase { final Collection> plugins = nodePlugins(); if (cluster1 == null) { - cluster1 = new InternalTestCluster(randomLong(), createTempDir(), true, minNumDataNodes, maxNumDataNodes, + cluster1 = new InternalTestCluster(randomLong(), createTempDir(), true, true, minNumDataNodes, maxNumDataNodes, UUIDs.randomBase64UUID(random()), nodeConfigurationSource, 0, false, "cluster_1", plugins, Function.identity()); } if (cluster2 == null) { - cluster2 = new InternalTestCluster(randomLong(), createTempDir(), true, minNumDataNodes, maxNumDataNodes, + cluster2 = new InternalTestCluster(randomLong(), createTempDir(), true, true, minNumDataNodes, maxNumDataNodes, UUIDs.randomBase64UUID(random()), nodeConfigurationSource, 0, false, "cluster_2", plugins, Function.identity()); } diff --git a/plugins/discovery-azure-classic/src/test/java/org/elasticsearch/discovery/azure/classic/AzureMinimumMasterNodesTests.java b/plugins/discovery-azure-classic/src/test/java/org/elasticsearch/discovery/azure/classic/AzureMinimumMasterNodesTests.java index 72e1f2da791..f8b105884bf 100644 --- a/plugins/discovery-azure-classic/src/test/java/org/elasticsearch/discovery/azure/classic/AzureMinimumMasterNodesTests.java +++ b/plugins/discovery-azure-classic/src/test/java/org/elasticsearch/discovery/azure/classic/AzureMinimumMasterNodesTests.java @@ -39,7 +39,8 @@ import static org.hamcrest.Matchers.nullValue; @ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.SUITE, numDataNodes = 0, transportClientRatio = 0.0, - numClientNodes = 0) + numClientNodes = 0, + autoMinMasterNodes = false) @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch-cloud-azure/issues/89") public class AzureMinimumMasterNodesTests extends AbstractAzureComputeServiceTestCase { diff --git a/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryUpdateSettingsTests.java b/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryUpdateSettingsTests.java index cdb45bfe087..41f5af48eb4 100644 --- a/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryUpdateSettingsTests.java +++ b/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryUpdateSettingsTests.java @@ -33,7 +33,7 @@ import static org.hamcrest.CoreMatchers.is; * starting. * This test requires AWS to run. */ -@ClusterScope(scope = Scope.TEST, numDataNodes = 0, numClientNodes = 0, transportClientRatio = 0.0) +@ClusterScope(scope = Scope.TEST, numDataNodes = 0, numClientNodes = 0, transportClientRatio = 0.0, autoMinMasterNodes = false) public class Ec2DiscoveryUpdateSettingsTests extends AbstractAwsTestCase { public void testMinimumMasterNodesStart() { Settings nodeSettings = Settings.builder() diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java index 82e7ce072e0..29f77bc166a 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java @@ -149,6 +149,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.List; @@ -178,6 +179,7 @@ import static org.elasticsearch.test.XContentTestUtils.differenceBetweenMapsIgno import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout; +import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.emptyArray; import static org.hamcrest.Matchers.emptyIterable; import static org.hamcrest.Matchers.equalTo; @@ -527,10 +529,15 @@ public abstract class ESIntegTestCase extends ESTestCase { if (cluster() != null) { if (currentClusterScope != Scope.TEST) { MetaData metaData = client().admin().cluster().prepareState().execute().actionGet().getState().getMetaData(); - assertThat("test leaves persistent cluster metadata behind: " + metaData.persistentSettings().getAsMap(), metaData - .persistentSettings().getAsMap().size(), equalTo(0)); - assertThat("test leaves transient cluster metadata behind: " + metaData.transientSettings().getAsMap(), metaData - .transientSettings().getAsMap().size(), equalTo(0)); + final Map persistent = metaData.persistentSettings().getAsMap(); + assertThat("test leaves persistent cluster metadata behind: " + persistent, persistent.size(), equalTo(0)); + final Map transientSettings = new HashMap<>(metaData.transientSettings().getAsMap()); + if (isInternalCluster() && internalCluster().getAutoManageMinMasterNode()) { + // this is set by the test infra + transientSettings.remove(ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey()); + } + assertThat("test leaves transient cluster metadata behind: " + transientSettings, + transientSettings.keySet(), empty()); } ensureClusterSizeConsistency(); ensureClusterStateConsistency(); @@ -1518,6 +1525,12 @@ public abstract class ESIntegTestCase extends ESTestCase { */ boolean supportsDedicatedMasters() default true; + /** + * The cluster automatically manages the {@link ElectMasterService#DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING} by default + * as nodes are started and stopped. Set this to false to manage the setting manually. + */ + boolean autoMinMasterNodes() default true; + /** * Returns the number of client nodes in the cluster. Default is {@link InternalTestCluster#DEFAULT_NUM_CLIENT_NODES}, a * negative value means that the number of client nodes will be randomized. @@ -1615,6 +1628,11 @@ public abstract class ESIntegTestCase extends ESTestCase { return annotation == null ? true : annotation.supportsDedicatedMasters(); } + private boolean getAutoMinMasterNodes() { + ClusterScope annotation = getAnnotation(this.getClass(), ClusterScope.class); + return annotation == null ? true : annotation.autoMinMasterNodes(); + } + private int getNumDataNodes() { ClusterScope annotation = getAnnotation(this.getClass(), ClusterScope.class); return annotation == null ? -1 : annotation.numDataNodes(); @@ -1753,7 +1771,8 @@ public abstract class ESIntegTestCase extends ESTestCase { } mockPlugins = mocks; } - return new InternalTestCluster(seed, createTempDir(), supportsDedicatedMasters, minNumDataNodes, maxNumDataNodes, + return new InternalTestCluster(seed, createTempDir(), supportsDedicatedMasters, getAutoMinMasterNodes(), + minNumDataNodes, maxNumDataNodes, InternalTestCluster.clusterName(scope.name(), seed) + "-cluster", nodeConfigurationSource, getNumClientNodes(), InternalTestCluster.DEFAULT_ENABLE_HTTP_PIPELINING, nodePrefix, mockPlugins, getClientWrapper()); } diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java index 69c59086980..1d3b24b3ce2 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java @@ -444,7 +444,6 @@ public abstract class ESTestCase extends LuceneTestCase { return RandomPicks.randomFrom(random, array); } - /** Pick a random object from the given list. */ public static T randomFrom(List list) { return RandomPicks.randomFrom(random(), list); @@ -452,7 +451,12 @@ public abstract class ESTestCase extends LuceneTestCase { /** Pick a random object from the given collection. */ public static T randomFrom(Collection collection) { - return RandomPicks.randomFrom(random(), collection); + return randomFrom(random(), collection); + } + + /** Pick a random object from the given collection. */ + public static T randomFrom(Random random, Collection collection) { + return RandomPicks.randomFrom(random, collection); } public static String randomAsciiOfLengthBetween(int minCodeUnits, int maxCodeUnits) { 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 37e3a58295e..3c29b878e7a 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java +++ b/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java @@ -24,12 +24,10 @@ import com.carrotsearch.randomizedtesting.SysGlobals; import com.carrotsearch.randomizedtesting.generators.RandomNumbers; import com.carrotsearch.randomizedtesting.generators.RandomPicks; import com.carrotsearch.randomizedtesting.generators.RandomStrings; - import org.apache.logging.log4j.Logger; import org.apache.lucene.store.StoreRateLimiting; import org.apache.lucene.util.IOUtils; import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.Version; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.cluster.node.stats.NodeStats; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse; @@ -68,7 +66,8 @@ import org.elasticsearch.common.util.concurrent.EsExecutors; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; -import org.elasticsearch.discovery.DiscoverySettings; +import org.elasticsearch.discovery.zen.ElectMasterService; +import org.elasticsearch.discovery.zen.ZenDiscovery; import org.elasticsearch.env.Environment; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.env.ShardLockObtainFailedException; @@ -133,8 +132,10 @@ import java.util.stream.Stream; import static org.apache.lucene.util.LuceneTestCase.TEST_NIGHTLY; import static org.apache.lucene.util.LuceneTestCase.rarely; +import static org.elasticsearch.discovery.DiscoverySettings.INITIAL_STATE_TIMEOUT_SETTING; import static org.elasticsearch.test.ESTestCase.assertBusy; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout; +import static org.elasticsearch.test.ESTestCase.randomFrom; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.greaterThanOrEqualTo; @@ -225,6 +226,8 @@ public final class InternalTestCluster extends TestCluster { private final ExecutorService executor; + private final boolean autoManageMinMasterNodes; + private final Collection> mockPlugins; /** @@ -238,9 +241,10 @@ public final class InternalTestCluster extends TestCluster { public InternalTestCluster(long clusterSeed, Path baseDir, boolean randomlyAddDedicatedMasters, - int minNumDataNodes, int maxNumDataNodes, String clusterName, NodeConfigurationSource nodeConfigurationSource, int numClientNodes, + boolean autoManageMinMasterNodes, int minNumDataNodes, int maxNumDataNodes, String clusterName, NodeConfigurationSource nodeConfigurationSource, int numClientNodes, boolean enableHttpPipelining, String nodePrefix, Collection> mockPlugins, Function clientWrapper) { super(clusterSeed); + this.autoManageMinMasterNodes = autoManageMinMasterNodes; this.clientWrapper = clientWrapper; this.baseDir = baseDir; this.clusterName = clusterName; @@ -345,6 +349,11 @@ public final class InternalTestCluster extends TestCluster { return clusterName; } + /** returns true if the {@link ElectMasterService#DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING} setting is auto managed by this cluster */ + public boolean getAutoManageMinMasterNode() { + return autoManageMinMasterNodes; + } + public String[] getNodeNames() { return nodes.keySet().toArray(Strings.EMPTY_ARRAY); } @@ -466,7 +475,7 @@ public final class InternalTestCluster extends TestCluster { if (randomNodeAndClient != null) { return randomNodeAndClient; } - NodeAndClient buildNode = buildNode(); + NodeAndClient buildNode = buildNode(1); buildNode.startNode(); publishNode(buildNode); return buildNode; @@ -496,30 +505,20 @@ public final class InternalTestCluster extends TestCluster { * if more nodes than n are present this method will not * stop any of the running nodes. */ - public void ensureAtLeastNumDataNodes(int n) { - final List> asyncs = new ArrayList<>(); - synchronized (this) { - int size = numDataNodes(); - for (int i = size; i < n; i++) { - logger.info("increasing cluster size from {} to {}", size, n); - if (numSharedDedicatedMasterNodes > 0) { - asyncs.add(startDataOnlyNodeAsync()); - } else { - asyncs.add(startNodeAsync()); - } + public synchronized void ensureAtLeastNumDataNodes(int n) { + boolean added = false; + int size = numDataNodes(); + for (int i = size; i < n; i++) { + logger.info("increasing cluster size from {} to {}", size, n); + added = true; + if (numSharedDedicatedMasterNodes > 0) { + startDataOnlyNode(Settings.EMPTY); + } else { + startNode(Settings.EMPTY); } } - try { - for (Async async : asyncs) { - async.get(); - } - } catch (Exception e) { - throw new ElasticsearchException("failed to start nodes", e); - } - if (!asyncs.isEmpty()) { - synchronized (this) { - assertNoTimeout(client().admin().cluster().prepareHealth().setWaitForNodes(Integer.toString(nodes.size())).get()); - } + if (added) { + validateClusterFormed(); } } @@ -544,28 +543,47 @@ public final class InternalTestCluster extends TestCluster { while (values.hasNext() && numNodesAndClients++ < size - n) { NodeAndClient next = values.next(); nodesToRemove.add(next); - removeDisruptionSchemeFromNode(next); - next.close(); - } - for (NodeAndClient toRemove : nodesToRemove) { - nodes.remove(toRemove.name); } + + stopNodesAndClients(nodesToRemove); if (!nodesToRemove.isEmpty() && size() > 0) { - assertNoTimeout(client().admin().cluster().prepareHealth().setWaitForNodes(Integer.toString(nodes.size())).get()); + validateClusterFormed(); } } - private NodeAndClient buildNode(Settings settings) { + /** + * builds a new node given the settings. + * + * @param settings the settings to use + * @param defaultMinMasterNodes min_master_nodes value to use if min_master_nodes is auto managed + */ + private NodeAndClient buildNode(Settings settings, int defaultMinMasterNodes) { int ord = nextNodeId.getAndIncrement(); - return buildNode(ord, random.nextLong(), settings, false); + return buildNode(ord, random.nextLong(), settings, false, defaultMinMasterNodes); } - private NodeAndClient buildNode() { + /** + * builds a new node with default settings + * + * @param defaultMinMasterNodes min_master_nodes value to use if min_master_nodes is auto managed + */ + private NodeAndClient buildNode(int defaultMinMasterNodes) { int ord = nextNodeId.getAndIncrement(); - return buildNode(ord, random.nextLong(), null, false); + return buildNode(ord, random.nextLong(), null, false, defaultMinMasterNodes); } - private NodeAndClient buildNode(int nodeId, long seed, Settings settings, boolean reuseExisting) { + /** + * builds a new node + * + * @param nodeId the node internal id (see {@link NodeAndClient#nodeAndClientId()} + * @param seed the node's random seed + * @param settings the settings to use + * @param reuseExisting if a node with the same name is already part of {@link #nodes}, no new node will be built and + * the method will return the existing one + * @param defaultMinMasterNodes min_master_nodes value to use if min_master_nodes is auto managed + */ + private NodeAndClient buildNode(int nodeId, long seed, Settings settings, + boolean reuseExisting, int defaultMinMasterNodes) { assert Thread.holdsLock(this); ensureOpen(); settings = getSettings(nodeId, seed, settings); @@ -577,13 +595,21 @@ public final class InternalTestCluster extends TestCluster { assert reuseExisting == true || nodes.containsKey(name) == false : "node name [" + name + "] already exists but not allowed to use it"; } - Settings finalSettings = Settings.builder() + Settings.Builder finalSettings = Settings.builder() .put(Environment.PATH_HOME_SETTING.getKey(), baseDir) // allow overriding path.home .put(settings) .put("node.name", name) - .put(NodeEnvironment.NODE_ID_SEED_SETTING.getKey(), seed) - .build(); - MockNode node = new MockNode(finalSettings, plugins); + .put(NodeEnvironment.NODE_ID_SEED_SETTING.getKey(), seed); + + if (autoManageMinMasterNodes) { + assert finalSettings.get(ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey()) == null : + "min master nodes may not be set when auto managed"; + finalSettings + // don't wait too long not to slow down tests + .put(ZenDiscovery.MASTER_ELECTION_WAIT_FOR_JOINS_TIMEOUT_SETTING.getKey(), "5s") + .put(ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey(), defaultMinMasterNodes); + } + MockNode node = new MockNode(finalSettings.build(), plugins); return new NodeAndClient(name, node, nodeId); } @@ -684,7 +710,7 @@ public final class InternalTestCluster extends TestCluster { .put(Node.NODE_DATA_SETTING.getKey(), false).put(Node.NODE_INGEST_SETTING.getKey(), false); if (size() == 0) { // if we are the first node - don't wait for a state - builder.put(DiscoverySettings.INITIAL_STATE_TIMEOUT_SETTING.getKey(), 0); + builder.put(INITIAL_STATE_TIMEOUT_SETTING.getKey(), 0); } return startNode(builder); } @@ -777,6 +803,10 @@ public final class InternalTestCluster extends TestCluster { return nodeAndClientId; } + public boolean isMasterEligible() { + return Node.NODE_MASTER_SETTING.get(node.settings()); + } + Client client(Random random) { if (closed.get()) { throw new RuntimeException("already closed"); @@ -844,21 +874,40 @@ public final class InternalTestCluster extends TestCluster { node.close(); } - void restart(RestartCallback callback, boolean clearDataIfNeeded) throws Exception { - assert callback != null; - resetClient(); + /** + * closes the current node if not already closed, builds a new node object using the current node settings and starts it + */ + void restart(RestartCallback callback, boolean clearDataIfNeeded, int minMasterNodes) throws Exception { if (!node.isClosed()) { closeNode(); } - Settings newSettings = callback.onNodeStopped(name); - if (newSettings == null) { - newSettings = Settings.EMPTY; + recreateNodeOnRestart(callback, clearDataIfNeeded, minMasterNodes); + startNode(); + } + + /** + * rebuilds a new node object using the current node settings and starts it + */ + void recreateNodeOnRestart(RestartCallback callback, boolean clearDataIfNeeded, int minMasterNodes) throws Exception { + assert callback != null; + Settings callbackSettings = callback.onNodeStopped(name); + Settings.Builder newSettings = Settings.builder(); + if (callbackSettings != null) { + newSettings.put(callbackSettings); } + if (minMasterNodes >= 0) { + assert ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.exists(newSettings.build()) == false : "min master nodes is auto managed"; + newSettings.put(ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey(), minMasterNodes).build(); + } + + // validation is (optionally) done in fullRestart/rollingRestart + newSettings.put(INITIAL_STATE_TIMEOUT_SETTING.getKey(), "0s"); if (clearDataIfNeeded) { clearDataIfNeeded(callback); } - createNewNode(newSettings); - startNode(); + createNewNode(newSettings.build()); + // make sure cached client points to new node + resetClient(); } private void clearDataIfNeeded(RestartCallback callback) throws IOException { @@ -948,22 +997,24 @@ public final class InternalTestCluster extends TestCluster { if (wipeData) { wipePendingDataDirectories(); } + if (nodes.size() > 0 && autoManageMinMasterNodes) { + updateMinMasterNodes(getMasterNodesCount()); + } logger.debug("Cluster hasn't changed - moving out - nodes: [{}] nextNodeId: [{}] numSharedNodes: [{}]", nodes.keySet(), nextNodeId.get(), newSize); return; } logger.debug("Cluster is NOT consistent - restarting shared nodes - nodes: [{}] nextNodeId: [{}] numSharedNodes: [{}]", nodes.keySet(), nextNodeId.get(), newSize); // trash all nodes with id >= sharedNodesSeeds.length - they are non shared - - + final List toClose = new ArrayList<>(); for (Iterator iterator = nodes.values().iterator(); iterator.hasNext();) { NodeAndClient nodeAndClient = iterator.next(); if (nodeAndClient.nodeAndClientId() >= sharedNodesSeeds.length) { logger.debug("Close Node [{}] not shared", nodeAndClient.name); - nodeAndClient.close(); - iterator.remove(); + toClose.add(nodeAndClient); } } + stopNodesAndClients(toClose); // clean up what the nodes left that is unused if (wipeData) { @@ -972,13 +1023,19 @@ public final class InternalTestCluster extends TestCluster { // start any missing node assert newSize == numSharedDedicatedMasterNodes + numSharedDataNodes + numSharedCoordOnlyNodes; + final int numberOfMasterNodes = numSharedDedicatedMasterNodes > 0 ? numSharedDedicatedMasterNodes : numSharedDataNodes; + final int defaultMinMasterNodes = (numberOfMasterNodes / 2) + 1; + final List toStartAndPublish = new ArrayList<>(); // we want to start nodes in one go due to min master nodes for (int i = 0; i < numSharedDedicatedMasterNodes; i++) { final Settings.Builder settings = Settings.builder(); - settings.put(Node.NODE_MASTER_SETTING.getKey(), true).build(); - settings.put(Node.NODE_DATA_SETTING.getKey(), false).build(); - NodeAndClient nodeAndClient = buildNode(i, sharedNodesSeeds[i], settings.build(), true); - nodeAndClient.startNode(); - publishNode(nodeAndClient); + settings.put(Node.NODE_MASTER_SETTING.getKey(), true); + settings.put(Node.NODE_DATA_SETTING.getKey(), false); + if (autoManageMinMasterNodes) { + settings.put(INITIAL_STATE_TIMEOUT_SETTING.getKey(), "0s"); // we wait at the end + } + + NodeAndClient nodeAndClient = buildNode(i, sharedNodesSeeds[i], settings.build(), true, defaultMinMasterNodes); + toStartAndPublish.add(nodeAndClient); } for (int i = numSharedDedicatedMasterNodes; i < numSharedDedicatedMasterNodes + numSharedDataNodes; i++) { final Settings.Builder settings = Settings.builder(); @@ -987,32 +1044,43 @@ public final class InternalTestCluster extends TestCluster { settings.put(Node.NODE_MASTER_SETTING.getKey(), false).build(); settings.put(Node.NODE_DATA_SETTING.getKey(), true).build(); } - NodeAndClient nodeAndClient = buildNode(i, sharedNodesSeeds[i], settings.build(), true); - nodeAndClient.startNode(); - publishNode(nodeAndClient); + if (autoManageMinMasterNodes) { + settings.put(INITIAL_STATE_TIMEOUT_SETTING.getKey(), "0s"); // we wait at the end + } + NodeAndClient nodeAndClient = buildNode(i, sharedNodesSeeds[i], settings.build(), true, defaultMinMasterNodes); + toStartAndPublish.add(nodeAndClient); } for (int i = numSharedDedicatedMasterNodes + numSharedDataNodes; i < numSharedDedicatedMasterNodes + numSharedDataNodes + numSharedCoordOnlyNodes; i++) { final Builder settings = Settings.builder().put(Node.NODE_MASTER_SETTING.getKey(), false) .put(Node.NODE_DATA_SETTING.getKey(), false).put(Node.NODE_INGEST_SETTING.getKey(), false); - NodeAndClient nodeAndClient = buildNode(i, sharedNodesSeeds[i], settings.build(), true); - nodeAndClient.startNode(); - publishNode(nodeAndClient); + NodeAndClient nodeAndClient = buildNode(i, sharedNodesSeeds[i], settings.build(), true, defaultMinMasterNodes); + toStartAndPublish.add(nodeAndClient); } + startAndPublishNodesAndClients(toStartAndPublish); + nextNodeId.set(newSize); assert size() == newSize; if (newSize > 0) { - ClusterHealthResponse response = client().admin().cluster().prepareHealth() - .setWaitForNodes(Integer.toString(newSize)).get(); - if (response.isTimedOut()) { - logger.warn("failed to wait for a cluster of size [{}], got [{}]", newSize, response); - throw new IllegalStateException("cluster failed to reach the expected size of [" + newSize + "]"); - } + validateClusterFormed(); } logger.debug("Cluster is consistent again - nodes: [{}] nextNodeId: [{}] numSharedNodes: [{}]", nodes.keySet(), nextNodeId.get(), newSize); } + /** ensure a cluster is form with {@link #nodes}.size() nodes. */ + private void validateClusterFormed() { + final int size = nodes.size(); + String name = randomFrom(random, getNodeNames()); + logger.trace("validating cluster formed via [{}], expecting [{}]", name, size); + final Client client = client(name); + ClusterHealthResponse response = client.admin().cluster().prepareHealth().setWaitForNodes(Integer.toString(size)).get(); + if (response.isTimedOut()) { + logger.warn("failed to wait for a cluster of size [{}], got [{}]", size, response); + throw new IllegalStateException("cluster failed to reach the expected size of [" + size + "]"); + } + } + @Override public synchronized void afterTest() throws IOException { wipePendingDataDirectories(); @@ -1234,9 +1302,7 @@ public final class InternalTestCluster extends TestCluster { NodeAndClient nodeAndClient = getRandomNodeAndClient(new DataNodePredicate()); if (nodeAndClient != null) { logger.info("Closing random node [{}] ", nodeAndClient.name); - removeDisruptionSchemeFromNode(nodeAndClient); - nodes.remove(nodeAndClient.name); - nodeAndClient.close(); + stopNodesAndClient(nodeAndClient); return true; } return false; @@ -1251,9 +1317,7 @@ public final class InternalTestCluster extends TestCluster { NodeAndClient nodeAndClient = getRandomNodeAndClient(nc -> filter.test(nc.node.settings())); if (nodeAndClient != null) { logger.info("Closing filtered random node [{}] ", nodeAndClient.name); - removeDisruptionSchemeFromNode(nodeAndClient); - nodes.remove(nodeAndClient.name); - nodeAndClient.close(); + stopNodesAndClient(nodeAndClient); } } @@ -1266,9 +1330,7 @@ public final class InternalTestCluster extends TestCluster { String masterNodeName = getMasterName(); assert nodes.containsKey(masterNodeName); logger.info("Closing master node [{}] ", masterNodeName); - removeDisruptionSchemeFromNode(nodes.get(masterNodeName)); - NodeAndClient remove = nodes.remove(masterNodeName); - remove.close(); + stopNodesAndClient(nodes.get(masterNodeName)); } /** @@ -1278,8 +1340,47 @@ public final class InternalTestCluster extends TestCluster { NodeAndClient nodeAndClient = getRandomNodeAndClient(new MasterNodePredicate(getMasterName()).negate()); if (nodeAndClient != null) { logger.info("Closing random non master node [{}] current master [{}] ", nodeAndClient.name, getMasterName()); + stopNodesAndClient(nodeAndClient); + } + } + + private synchronized void startAndPublishNodesAndClients(List nodeAndClients) { + if (nodeAndClients.size() > 0) { + final int newMasters = (int) nodeAndClients.stream().filter(NodeAndClient::isMasterEligible) + .filter(nac -> nodes.containsKey(nac.name) == false) // filter out old masters + .count(); + final int currentMasters = getMasterNodesCount(); + if (autoManageMinMasterNodes && currentMasters > 1 && newMasters > 0) { + // special case for 1 node master - we can't update the min master nodes before we add more nodes. + updateMinMasterNodes(currentMasters + newMasters); + } + for (NodeAndClient nodeAndClient : nodeAndClients) { + nodeAndClient.startNode(); + publishNode(nodeAndClient); + } + if (autoManageMinMasterNodes && currentMasters == 1 && newMasters > 0) { + // update once masters have joined + validateClusterFormed(); + updateMinMasterNodes(currentMasters + newMasters); + } + } + } + + private synchronized void stopNodesAndClient(NodeAndClient nodeAndClient) throws IOException { + stopNodesAndClients(Collections.singleton(nodeAndClient)); + } + + private synchronized void stopNodesAndClients(Collection nodeAndClients) throws IOException { + if (autoManageMinMasterNodes && nodeAndClients.size() > 0) { + int masters = (int)nodeAndClients.stream().filter(NodeAndClient::isMasterEligible).count(); + if (masters > 0) { + updateMinMasterNodes(getMasterNodesCount() - masters); + } + } + for (NodeAndClient nodeAndClient: nodeAndClients) { removeDisruptionSchemeFromNode(nodeAndClient); - nodes.remove(nodeAndClient.name); + NodeAndClient previous = nodes.remove(nodeAndClient.name); + assert previous == nodeAndClient; nodeAndClient.close(); } } @@ -1319,8 +1420,7 @@ public final class InternalTestCluster extends TestCluster { ensureOpen(); NodeAndClient nodeAndClient = getRandomNodeAndClient(predicate); if (nodeAndClient != null) { - logger.info("Restarting random node [{}] ", nodeAndClient.name); - nodeAndClient.restart(callback, true); + restartNode(nodeAndClient, callback); } } @@ -1331,93 +1431,10 @@ public final class InternalTestCluster extends TestCluster { ensureOpen(); NodeAndClient nodeAndClient = nodes.get(nodeName); if (nodeAndClient != null) { - logger.info("Restarting node [{}] ", nodeAndClient.name); - nodeAndClient.restart(callback, true); + restartNode(nodeAndClient, callback); } } - private synchronized void restartAllNodes(boolean rollingRestart, RestartCallback callback) throws Exception { - ensureOpen(); - List toRemove = new ArrayList<>(); - try { - for (NodeAndClient nodeAndClient : nodes.values()) { - if (!callback.doRestart(nodeAndClient.name)) { - logger.info("Closing node [{}] during restart", nodeAndClient.name); - toRemove.add(nodeAndClient); - if (activeDisruptionScheme != null) { - activeDisruptionScheme.removeFromNode(nodeAndClient.name, this); - } - nodeAndClient.close(); - } - } - } finally { - for (NodeAndClient nodeAndClient : toRemove) { - nodes.remove(nodeAndClient.name); - } - } - logger.info("Restarting remaining nodes rollingRestart [{}]", rollingRestart); - if (rollingRestart) { - int numNodesRestarted = 0; - for (NodeAndClient nodeAndClient : nodes.values()) { - callback.doAfterNodes(numNodesRestarted++, nodeAndClient.nodeClient()); - logger.info("Restarting node [{}] ", nodeAndClient.name); - if (activeDisruptionScheme != null) { - activeDisruptionScheme.removeFromNode(nodeAndClient.name, this); - } - nodeAndClient.restart(callback, true); - if (activeDisruptionScheme != null) { - activeDisruptionScheme.applyToNode(nodeAndClient.name, this); - } - } - } else { - int numNodesRestarted = 0; - Set[] nodesRoleOrder = new Set[nextNodeId.get()]; - Map, List> nodesByRoles = new HashMap<>(); - for (NodeAndClient nodeAndClient : nodes.values()) { - callback.doAfterNodes(numNodesRestarted++, nodeAndClient.nodeClient()); - logger.info("Stopping node [{}] ", nodeAndClient.name); - if (activeDisruptionScheme != null) { - activeDisruptionScheme.removeFromNode(nodeAndClient.name, this); - } - nodeAndClient.closeNode(); - // delete data folders now, before we start other nodes that may claim it - nodeAndClient.clearDataIfNeeded(callback); - - DiscoveryNode discoveryNode = getInstanceFromNode(ClusterService.class, nodeAndClient.node()).localNode(); - nodesRoleOrder[nodeAndClient.nodeAndClientId()] = discoveryNode.getRoles(); - nodesByRoles.computeIfAbsent(discoveryNode.getRoles(), k -> new ArrayList<>()).add(nodeAndClient); - } - - assert nodesByRoles.values().stream().collect(Collectors.summingInt(List::size)) == nodes.size(); - - // randomize start up order, but making sure that: - // 1) A data folder that was assigned to a data node will stay so - // 2) Data nodes will get the same node lock ordinal range, so custom index paths (where the ordinal is used) - // will still belong to data nodes - for (List sameRoleNodes : nodesByRoles.values()) { - Collections.shuffle(sameRoleNodes, random); - } - - for (Set roles : nodesRoleOrder) { - if (roles == null) { - // if some nodes were stopped, we want have a role for them - continue; - } - NodeAndClient nodeAndClient = nodesByRoles.get(roles).remove(0); - logger.info("Starting node [{}] ", nodeAndClient.name); - if (activeDisruptionScheme != null) { - activeDisruptionScheme.removeFromNode(nodeAndClient.name, this); - } - // we already cleared data folders, before starting nodes up - nodeAndClient.restart(callback, false); - if (activeDisruptionScheme != null) { - activeDisruptionScheme.applyToNode(nodeAndClient.name, this); - } - } - } - } - - public static final RestartCallback EMPTY_CALLBACK = new RestartCallback() { @Override public Settings onNodeStopped(String node) { @@ -1442,15 +1459,98 @@ public final class InternalTestCluster extends TestCluster { /** * Restarts all nodes in a rolling restart fashion ie. only restarts on node a time. */ - public void rollingRestart(RestartCallback function) throws Exception { - restartAllNodes(true, function); + public synchronized void rollingRestart(RestartCallback callback) throws Exception { + int numNodesRestarted = 0; + for (NodeAndClient nodeAndClient : nodes.values()) { + callback.doAfterNodes(numNodesRestarted++, nodeAndClient.nodeClient()); + restartNode(nodeAndClient, callback); + } + } + + private void restartNode(NodeAndClient nodeAndClient, RestartCallback callback) throws Exception { + logger.info("Restarting node [{}] ", nodeAndClient.name); + if (activeDisruptionScheme != null) { + activeDisruptionScheme.removeFromNode(nodeAndClient.name, this); + } + final int masterNodesCount = getMasterNodesCount(); + // special case to allow stopping one node in a two node cluster and keep it functional + final boolean updateMinMaster = nodeAndClient.isMasterEligible() && masterNodesCount == 2 && autoManageMinMasterNodes; + if (updateMinMaster) { + updateMinMasterNodes(masterNodesCount - 1); + } + nodeAndClient.restart(callback, true, autoManageMinMasterNodes ? getMinMasterNodes(masterNodesCount) : -1); + if (activeDisruptionScheme != null) { + activeDisruptionScheme.applyToNode(nodeAndClient.name, this); + } + if (callback.validateClusterForming() || updateMinMaster) { + // we have to validate cluster size if updateMinMaster == true, because we need the + // second node to join in order to increment min_master_nodes back to 2. + validateClusterFormed(); + } + if (updateMinMaster) { + updateMinMasterNodes(masterNodesCount); + } } /** * Restarts all nodes in the cluster. It first stops all nodes and then restarts all the nodes again. */ - public void fullRestart(RestartCallback function) throws Exception { - restartAllNodes(false, function); + public synchronized void fullRestart(RestartCallback callback) throws Exception { + int numNodesRestarted = 0; + Map, List> nodesByRoles = new HashMap<>(); + Set[] rolesOrderedByOriginalStartupOrder = new Set[nextNodeId.get()]; + for (NodeAndClient nodeAndClient : nodes.values()) { + callback.doAfterNodes(numNodesRestarted++, nodeAndClient.nodeClient()); + logger.info("Stopping node [{}] ", nodeAndClient.name); + if (activeDisruptionScheme != null) { + activeDisruptionScheme.removeFromNode(nodeAndClient.name, this); + } + nodeAndClient.closeNode(); + // delete data folders now, before we start other nodes that may claim it + nodeAndClient.clearDataIfNeeded(callback); + DiscoveryNode discoveryNode = getInstanceFromNode(ClusterService.class, nodeAndClient.node()).localNode(); + rolesOrderedByOriginalStartupOrder[nodeAndClient.nodeAndClientId] = discoveryNode.getRoles(); + nodesByRoles.computeIfAbsent(discoveryNode.getRoles(), k -> new ArrayList<>()).add(nodeAndClient); + } + + assert nodesByRoles.values().stream().collect(Collectors.summingInt(List::size)) == nodes.size(); + + // randomize start up order, but making sure that: + // 1) A data folder that was assigned to a data node will stay so + // 2) Data nodes will get the same node lock ordinal range, so custom index paths (where the ordinal is used) + // will still belong to data nodes + for (List sameRoleNodes : nodesByRoles.values()) { + Collections.shuffle(sameRoleNodes, random); + } + List startUpOrder = new ArrayList<>(); + for (Set roles : rolesOrderedByOriginalStartupOrder) { + if (roles == null) { + // if some nodes were stopped, we want have a role for that ordinal + continue; + } + final List nodesByRole = nodesByRoles.get(roles); + startUpOrder.add(nodesByRole.remove(0)); + } + assert nodesByRoles.values().stream().collect(Collectors.summingInt(List::size)) == 0; + + // do two rounds to minimize pinging (mock zen pings pings with no delay and can create a lot of logs) + for (NodeAndClient nodeAndClient : startUpOrder) { + logger.info("resetting node [{}] ", nodeAndClient.name); + // we already cleared data folders, before starting nodes up + nodeAndClient.recreateNodeOnRestart(callback, false, autoManageMinMasterNodes ? getMinMasterNodes(getMasterNodesCount()) : -1); + } + + for (NodeAndClient nodeAndClient : startUpOrder) { + logger.info("starting node [{}] ", nodeAndClient.name); + nodeAndClient.startNode(); + if (activeDisruptionScheme != null) { + activeDisruptionScheme.applyToNode(nodeAndClient.name, this); + } + } + + if (callback.validateClusterForming()) { + validateClusterFormed(); + } } @@ -1534,19 +1634,51 @@ public final class InternalTestCluster extends TestCluster { * Starts a node with the given settings and returns it's name. */ public synchronized String startNode(Settings settings) { - NodeAndClient buildNode = buildNode(settings); - buildNode.startNode(); - publishNode(buildNode); + final int defaultMinMasterNodes = getMinMasterNodes(getMasterNodesCount() + (Node.NODE_MASTER_SETTING.get(settings) ? 1 : 0)); + NodeAndClient buildNode = buildNode(settings, defaultMinMasterNodes); + startAndPublishNodesAndClients(Collections.singletonList(buildNode)); return buildNode.name; } + /** + * updates the min master nodes setting in the current running cluster. + * + * @param eligibleMasterNodeCount the number of master eligible nodes to use as basis for the min master node setting + */ + private int updateMinMasterNodes(int eligibleMasterNodeCount) { + assert autoManageMinMasterNodes; + final int minMasterNodes = getMinMasterNodes(eligibleMasterNodeCount); + if (getMasterNodesCount() > 0) { + // there should be at least one master to update + logger.debug("updating min_master_nodes to [{}]", minMasterNodes); + try { + assertAcked(client().admin().cluster().prepareUpdateSettings().setTransientSettings( + Settings.builder().put(ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey(), minMasterNodes) + )); + } catch (Exception e) { + throw new ElasticsearchException("failed to update minimum master node to [{}] (current masters [{}])", e, + minMasterNodes, getMasterNodesCount()); + } + } + return minMasterNodes; + } + + /** calculates a min master nodes value based on the given number of master nodes */ + private int getMinMasterNodes(int eligibleMasterNodes) { + return eligibleMasterNodes / 2 + 1; + } + + private int getMasterNodesCount() { + return (int)nodes.values().stream().filter(n -> Node.NODE_MASTER_SETTING.get(n.node().settings())).count(); + } + public synchronized Async> startMasterOnlyNodesAsync(int numNodes) { return startMasterOnlyNodesAsync(numNodes, Settings.EMPTY); } public synchronized Async> startMasterOnlyNodesAsync(int numNodes, Settings settings) { Settings settings1 = Settings.builder().put(settings).put(Node.NODE_MASTER_SETTING.getKey(), true).put(Node.NODE_DATA_SETTING.getKey(), false).build(); - return startNodesAsync(numNodes, settings1, Version.CURRENT); + return startNodesAsync(numNodes, settings1); } public synchronized Async> startDataOnlyNodesAsync(int numNodes) { @@ -1555,7 +1687,7 @@ public final class InternalTestCluster extends TestCluster { public synchronized Async> startDataOnlyNodesAsync(int numNodes, Settings settings) { Settings settings1 = Settings.builder().put(settings).put(Node.NODE_MASTER_SETTING.getKey(), false).put(Node.NODE_DATA_SETTING.getKey(), true).build(); - return startNodesAsync(numNodes, settings1, Version.CURRENT); + return startNodesAsync(numNodes, settings1); } public synchronized Async startMasterOnlyNodeAsync() { @@ -1564,7 +1696,7 @@ public final class InternalTestCluster extends TestCluster { public synchronized Async startMasterOnlyNodeAsync(Settings settings) { Settings settings1 = Settings.builder().put(settings).put(Node.NODE_MASTER_SETTING.getKey(), true).put(Node.NODE_DATA_SETTING.getKey(), false).build(); - return startNodeAsync(settings1, Version.CURRENT); + return startNodeAsync(settings1); } public synchronized String startMasterOnlyNode(Settings settings) { @@ -1578,7 +1710,7 @@ public final class InternalTestCluster extends TestCluster { public synchronized Async startDataOnlyNodeAsync(Settings settings) { Settings settings1 = Settings.builder().put(settings).put(Node.NODE_MASTER_SETTING.getKey(), false).put(Node.NODE_DATA_SETTING.getKey(), true).build(); - return startNodeAsync(settings1, Version.CURRENT); + return startNodeAsync(settings1); } public synchronized String startDataOnlyNode(Settings settings) { @@ -1590,21 +1722,25 @@ public final class InternalTestCluster extends TestCluster { * Starts a node in an async manner with the given settings and returns future with its name. */ public synchronized Async startNodeAsync() { - return startNodeAsync(Settings.EMPTY, Version.CURRENT); + return startNodeAsync(Settings.EMPTY); } /** * Starts a node in an async manner with the given settings and returns future with its name. */ public synchronized Async startNodeAsync(final Settings settings) { - return startNodeAsync(settings, Version.CURRENT); + final int defaultMinMasterNodes; + if (autoManageMinMasterNodes) { + int mastersDelta = Node.NODE_MASTER_SETTING.get(settings) ? 1 : 0; + defaultMinMasterNodes = updateMinMasterNodes(getMasterNodesCount() + mastersDelta); + } else { + defaultMinMasterNodes = -1; + } + return startNodeAsync(settings, defaultMinMasterNodes); } - /** - * Starts a node in an async manner with the given settings and version and returns future with its name. - */ - public synchronized Async startNodeAsync(final Settings settings, final Version version) { - final NodeAndClient buildNode = buildNode(settings); + private synchronized Async startNodeAsync(final Settings settings, int defaultMinMasterNodes) { + final NodeAndClient buildNode = buildNode(settings, defaultMinMasterNodes); final Future submit = executor.submit(() -> { buildNode.startNode(); publishNode(buildNode); @@ -1613,27 +1749,28 @@ public final class InternalTestCluster extends TestCluster { return () -> submit.get(); } + /** * Starts multiple nodes in an async manner and returns future with its name. */ public synchronized Async> startNodesAsync(final int numNodes) { - return startNodesAsync(numNodes, Settings.EMPTY, Version.CURRENT); + return startNodesAsync(numNodes, Settings.EMPTY); } /** * Starts multiple nodes in an async manner with the given settings and returns future with its name. */ - public synchronized Async> startNodesAsync(final int numNodes, final Settings settings) { - return startNodesAsync(numNodes, settings, Version.CURRENT); - } - - /** - * Starts multiple nodes in an async manner with the given settings and version and returns future with its name. - */ - public synchronized Async> startNodesAsync(final int numNodes, final Settings settings, final Version version) { + public synchronized Async> startNodesAsync(final int numNodes, final Settings settings) { + final int defaultMinMasterNodes; + if (autoManageMinMasterNodes) { + int mastersDelta = Node.NODE_MASTER_SETTING.get(settings) ? numNodes : 0; + defaultMinMasterNodes = updateMinMasterNodes(getMasterNodesCount() + mastersDelta); + } else { + defaultMinMasterNodes = -1; + } final List> asyncs = new ArrayList<>(); for (int i = 0; i < numNodes; i++) { - asyncs.add(startNodeAsync(settings, version)); + asyncs.add(startNodeAsync(settings, defaultMinMasterNodes)); } return () -> { @@ -1650,9 +1787,16 @@ public final class InternalTestCluster extends TestCluster { * The order of the node names returned matches the order of the settings provided. */ public synchronized Async> startNodesAsync(final Settings... settings) { + final int defaultMinMasterNodes; + if (autoManageMinMasterNodes) { + int mastersDelta = (int) Stream.of(settings).filter(Node.NODE_MASTER_SETTING::get).count(); + defaultMinMasterNodes = updateMinMasterNodes(getMasterNodesCount() + mastersDelta); + } else { + defaultMinMasterNodes = -1; + } List> asyncs = new ArrayList<>(); for (Settings setting : settings) { - asyncs.add(startNodeAsync(setting, Version.CURRENT)); + asyncs.add(startNodeAsync(setting, defaultMinMasterNodes)); } return () -> { List ids = new ArrayList<>(); @@ -1683,6 +1827,11 @@ public final class InternalTestCluster extends TestCluster { return dataAndMasterNodes().size(); } + public synchronized int numMasterNodes() { + return filterNodes(nodes, NodeAndClient::isMasterEligible).size(); + } + + public void setDisruptionScheme(ServiceDisruptionScheme scheme) { clearDisruptionScheme(); scheme.applyToCluster(this); @@ -1887,14 +2036,8 @@ public final class InternalTestCluster extends TestCluster { return false; } - - /** - * If this returns false the node with the given node name will not be restarted. It will be - * closed and removed from the cluster. Returns true by default. - */ - public boolean doRestart(String nodeName) { - return true; - } + /** returns true if the restart should also validate the cluster has reformed */ + public boolean validateClusterForming() { return true; } } public Settings getDefaultSettings() { diff --git a/test/framework/src/main/java/org/elasticsearch/test/discovery/MockZenPing.java b/test/framework/src/main/java/org/elasticsearch/test/discovery/MockZenPing.java index c544b2bad88..fe16f034116 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/discovery/MockZenPing.java +++ b/test/framework/src/main/java/org/elasticsearch/test/discovery/MockZenPing.java @@ -18,11 +18,6 @@ */ package org.elasticsearch.test.discovery; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.common.component.AbstractComponent; @@ -32,13 +27,22 @@ import org.elasticsearch.common.util.concurrent.ConcurrentCollections; import org.elasticsearch.discovery.zen.PingContextProvider; import org.elasticsearch.discovery.zen.ZenPing; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + /** * A {@link ZenPing} implementation which returns results based on an static in-memory map. This allows pinging * to be immediate and can be used to speed up tests. */ public final class MockZenPing extends AbstractComponent implements ZenPing { - static final Map> activeNodesPerCluster = ConcurrentCollections.newConcurrentMap(); + static final Map> activeNodesPerCluster = new HashMap<>(); + + /** a set of the last discovered pings. used to throttle busy spinning where MockZenPing will keep returning the same results */ + private Set lastDiscoveredPings = null; private volatile PingContextProvider contextProvider; @@ -50,18 +54,34 @@ public final class MockZenPing extends AbstractComponent implements ZenPing { public void start(PingContextProvider contextProvider) { this.contextProvider = contextProvider; assert contextProvider != null; - boolean added = getActiveNodesForCurrentCluster().add(this); - assert added; + synchronized (activeNodesPerCluster) { + boolean added = getActiveNodesForCurrentCluster().add(this); + assert added; + activeNodesPerCluster.notifyAll(); + } } @Override public void ping(PingListener listener, TimeValue timeout) { logger.info("pinging using mock zen ping"); - List responseList = getActiveNodesForCurrentCluster().stream() - .filter(p -> p != this) // remove this as pings are not expected to return the local node - .map(MockZenPing::getPingResponse) - .collect(Collectors.toList()); - listener.onPing(responseList); + synchronized (activeNodesPerCluster) { + Set activeNodes = getActiveNodesForCurrentCluster(); + if (activeNodes.equals(lastDiscoveredPings)) { + try { + logger.trace("nothing has changed since the last ping. waiting for a change"); + activeNodesPerCluster.wait(timeout.millis()); + } catch (InterruptedException e) { + + } + activeNodes = getActiveNodesForCurrentCluster(); + } + lastDiscoveredPings = activeNodes; + List responseList = activeNodes.stream() + .filter(p -> p != this) // remove this as pings are not expected to return the local node + .map(MockZenPing::getPingResponse) + .collect(Collectors.toList()); + listener.onPing(responseList); + } } private ClusterName getClusterName() { @@ -74,13 +94,17 @@ public final class MockZenPing extends AbstractComponent implements ZenPing { } private Set getActiveNodesForCurrentCluster() { + assert Thread.holdsLock(activeNodesPerCluster); return activeNodesPerCluster.computeIfAbsent(getClusterName(), clusterName -> ConcurrentCollections.newConcurrentSet()); } @Override public void close() { - boolean found = getActiveNodesForCurrentCluster().remove(this); - assert found; + synchronized (activeNodesPerCluster) { + boolean found = getActiveNodesForCurrentCluster().remove(this); + assert found; + activeNodesPerCluster.notifyAll(); + } } } diff --git a/test/framework/src/main/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java b/test/framework/src/main/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java index 8cff517316b..bc560c9b0f0 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java +++ b/test/framework/src/main/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java @@ -636,7 +636,7 @@ public class ElasticsearchAssertions { * a way that sucks less. */ NamedWriteableRegistry registry; - if (ESIntegTestCase.isInternalCluster()) { + if (ESIntegTestCase.isInternalCluster() && ESIntegTestCase.internalCluster().size() > 0) { registry = ESIntegTestCase.internalCluster().getInstance(NamedWriteableRegistry.class); } else { SearchModule searchModule = new SearchModule(Settings.EMPTY, false, emptyList()); diff --git a/test/framework/src/test/java/org/elasticsearch/test/test/InternalTestClusterTests.java b/test/framework/src/test/java/org/elasticsearch/test/test/InternalTestClusterTests.java index 327a49d3678..36903c7c608 100644 --- a/test/framework/src/test/java/org/elasticsearch/test/test/InternalTestClusterTests.java +++ b/test/framework/src/test/java/org/elasticsearch/test/test/InternalTestClusterTests.java @@ -19,21 +19,6 @@ */ package org.elasticsearch.test.test; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.LuceneTestCase; import org.elasticsearch.client.Client; @@ -51,14 +36,32 @@ import org.elasticsearch.test.NodeConfigurationSource; import org.elasticsearch.test.discovery.TestZenDiscovery; import org.elasticsearch.transport.MockTcpTransportPlugin; import org.elasticsearch.transport.TransportSettings; +import org.hamcrest.Matcher; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; import static org.elasticsearch.cluster.node.DiscoveryNode.Role.DATA; import static org.elasticsearch.cluster.node.DiscoveryNode.Role.INGEST; import static org.elasticsearch.cluster.node.DiscoveryNode.Role.MASTER; +import static org.elasticsearch.discovery.zen.ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFileExists; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFileNotExists; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.not; /** @@ -81,10 +84,10 @@ public class InternalTestClusterTests extends ESTestCase { Path baseDir = createTempDir(); InternalTestCluster cluster0 = new InternalTestCluster(clusterSeed, baseDir, masterNodes, - minNumDataNodes, maxNumDataNodes, clusterName, nodeConfigurationSource, numClientNodes, + randomBoolean(), minNumDataNodes, maxNumDataNodes, clusterName, nodeConfigurationSource, numClientNodes, enableHttpPipelining, nodePrefix, Collections.emptyList(), Function.identity()); InternalTestCluster cluster1 = new InternalTestCluster(clusterSeed, baseDir, masterNodes, - minNumDataNodes, maxNumDataNodes, clusterName, nodeConfigurationSource, numClientNodes, + randomBoolean(), minNumDataNodes, maxNumDataNodes, clusterName, nodeConfigurationSource, numClientNodes, enableHttpPipelining, nodePrefix, Collections.emptyList(), Function.identity()); // TODO: this is not ideal - we should have a way to make sure ports are initialized in the same way assertClusters(cluster0, cluster1, false); @@ -116,7 +119,8 @@ public class InternalTestClusterTests extends ESTestCase { public static void assertSettings(Settings left, Settings right, boolean checkClusterUniqueSettings) { Set> entries0 = left.getAsMap().entrySet(); Map entries1 = right.getAsMap(); - assertThat(entries0.size(), equalTo(entries1.size())); + assertThat("--> left:\n" + left.toDelimitedString('\n') + "\n-->right:\n" + right.toDelimitedString('\n'), + entries0.size(), equalTo(entries1.size())); for (Map.Entry entry : entries0) { if (clusterUniqueSettings.contains(entry.getKey()) && checkClusterUniqueSettings == false) { continue; @@ -125,6 +129,41 @@ public class InternalTestClusterTests extends ESTestCase { } } + private void assertMMNinNodeSetting(InternalTestCluster cluster, int masterNodes) { + for (final String node : cluster.getNodeNames()) { + assertMMNinNodeSetting(node, cluster, masterNodes); + } + } + + private void assertMMNinNodeSetting(String node, InternalTestCluster cluster, int masterNodes) { + final int minMasterNodes = masterNodes / 2 + 1; + final Matcher> minMasterMatcher = + hasEntry(DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey(), Integer.toString(minMasterNodes)); + final Matcher> noMinMasterNodesMatcher = not(hasKey(DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey())); + Settings nodeSettings = cluster.client(node).admin().cluster().prepareNodesInfo(node).get().getNodes().get(0).getSettings(); + assertThat("node setting of node [" + node + "] has the wrong min_master_node setting: [" + + nodeSettings.get(DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey()) + "]", + nodeSettings.getAsMap(), + cluster.getAutoManageMinMasterNode() ? minMasterMatcher: noMinMasterNodesMatcher); + } + + private void assertMMNinClusterSetting(InternalTestCluster cluster, int masterNodes) { + final int minMasterNodes = masterNodes / 2 + 1; + Matcher> minMasterMatcher = + hasEntry(DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey(), Integer.toString(minMasterNodes)); + Matcher> noMinMasterNodesMatcher = not(hasKey(DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey())); + + for (final String node : cluster.getNodeNames()) { + Settings stateSettings = cluster.client(node).admin().cluster().prepareState().setLocal(true) + .get().getState().getMetaData().settings(); + + assertThat("dynamic setting for node [" + node + "] has the wrong min_master_node setting : [" + + stateSettings.get(DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey()) + "]", + stateSettings.getAsMap(), + cluster.getAutoManageMinMasterNode() ? minMasterMatcher: noMinMasterNodesMatcher); + } + } + public void testBeforeTest() throws Exception { long clusterSeed = randomLong(); boolean masterNodes = randomBoolean(); @@ -156,11 +195,12 @@ public class InternalTestClusterTests extends ESTestCase { Path baseDir = createTempDir(); final List> mockPlugins = Arrays.asList(MockTcpTransportPlugin.class, TestZenDiscovery.TestPlugin.class); + final boolean autoManageMinMasterNodes = randomBoolean(); InternalTestCluster cluster0 = new InternalTestCluster(clusterSeed, baseDir, masterNodes, - minNumDataNodes, maxNumDataNodes, clusterName1, nodeConfigurationSource, numClientNodes, + autoManageMinMasterNodes, minNumDataNodes, maxNumDataNodes, clusterName1, nodeConfigurationSource, numClientNodes, enableHttpPipelining, nodePrefix, mockPlugins, Function.identity()); InternalTestCluster cluster1 = new InternalTestCluster(clusterSeed, baseDir, masterNodes, - minNumDataNodes, maxNumDataNodes, clusterName2, nodeConfigurationSource, numClientNodes, + autoManageMinMasterNodes, minNumDataNodes, maxNumDataNodes, clusterName2, nodeConfigurationSource, numClientNodes, enableHttpPipelining, nodePrefix, mockPlugins, Function.identity()); assertClusters(cluster0, cluster1, false); @@ -182,6 +222,8 @@ public class InternalTestClusterTests extends ESTestCase { assertSettings(client.settings(), other.settings(), false); } assertArrayEquals(cluster0.getNodeNames(), cluster1.getNodeNames()); + assertMMNinNodeSetting(cluster0, cluster0.numMasterNodes()); + assertMMNinNodeSetting(cluster1, cluster0.numMasterNodes()); cluster0.afterTest(); cluster1.afterTest(); } finally { @@ -216,12 +258,15 @@ public class InternalTestClusterTests extends ESTestCase { boolean enableHttpPipelining = randomBoolean(); String nodePrefix = "test"; Path baseDir = createTempDir(); + final boolean autoManageMinMasterNodes = randomBoolean(); InternalTestCluster cluster = new InternalTestCluster(clusterSeed, baseDir, masterNodes, - minNumDataNodes, maxNumDataNodes, clusterName1, nodeConfigurationSource, numClientNodes, + autoManageMinMasterNodes, minNumDataNodes, maxNumDataNodes, clusterName1, nodeConfigurationSource, numClientNodes, enableHttpPipelining, nodePrefix, Arrays.asList(MockTcpTransportPlugin.class, TestZenDiscovery.TestPlugin.class), Function.identity()); try { cluster.beforeTest(random(), 0.0); + final int originalMasterCount = cluster.numMasterNodes(); + assertMMNinNodeSetting(cluster, originalMasterCount); final Map shardNodePaths = new HashMap<>(); for (String name: cluster.getNodeNames()) { shardNodePaths.put(name, getNodePaths(cluster, name)); @@ -230,7 +275,15 @@ public class InternalTestClusterTests extends ESTestCase { Path dataPath = getNodePaths(cluster, poorNode)[0]; final Path testMarker = dataPath.resolve("testMarker"); Files.createDirectories(testMarker); + int expectedMasterCount = originalMasterCount; + if (cluster.getInstance(ClusterService.class, poorNode).localNode().isMasterNode()) { + expectedMasterCount--; + } cluster.stopRandomNode(InternalTestCluster.nameFilter(poorNode)); + if (expectedMasterCount != originalMasterCount) { + // check for updated + assertMMNinClusterSetting(cluster, expectedMasterCount); + } assertFileExists(testMarker); // stopping a node half way shouldn't clean data final String stableNode = randomFrom(cluster.getNodeNames()); @@ -240,10 +293,17 @@ public class InternalTestClusterTests extends ESTestCase { Files.createDirectories(stableTestMarker); final String newNode1 = cluster.startNode(); + expectedMasterCount++; assertThat(getNodePaths(cluster, newNode1)[0], equalTo(dataPath)); assertFileExists(testMarker); // starting a node should re-use data folders and not clean it + if (expectedMasterCount > 1) { // this is the first master, it's in cluster state settings won't be updated + assertMMNinClusterSetting(cluster, expectedMasterCount); + } + assertMMNinNodeSetting(newNode1, cluster, expectedMasterCount); final String newNode2 = cluster.startNode(); + expectedMasterCount++; + assertMMNinClusterSetting(cluster, expectedMasterCount); final Path newDataPath = getNodePaths(cluster, newNode2)[0]; final Path newTestMarker = newDataPath.resolve("newTestMarker"); assertThat(newDataPath, not(dataPath)); @@ -262,6 +322,7 @@ public class InternalTestClusterTests extends ESTestCase { assertThat("data paths for " + name + " changed", getNodePaths(cluster, name), equalTo(shardNodePaths.get(name))); } + assertMMNinNodeSetting(cluster, originalMasterCount); } finally { cluster.close(); @@ -280,7 +341,7 @@ public class InternalTestClusterTests extends ESTestCase { public void testDifferentRolesMaintainPathOnRestart() throws Exception { final Path baseDir = createTempDir(); final int numNodes = 5; - InternalTestCluster cluster = new InternalTestCluster(randomLong(), baseDir, true, 0, 0, "test", + InternalTestCluster cluster = new InternalTestCluster(randomLong(), baseDir, true, true, 0, 0, "test", new NodeConfigurationSource() { @Override public Settings nodeSettings(int nodeOrdinal) { @@ -301,7 +362,9 @@ public class InternalTestClusterTests extends ESTestCase { try { Map> pathsPerRole = new HashMap<>(); for (int i = 0; i < numNodes; i++) { - final DiscoveryNode.Role role = randomFrom(MASTER, DiscoveryNode.Role.DATA, DiscoveryNode.Role.INGEST); + final DiscoveryNode.Role role = i == numNodes -1 && pathsPerRole.containsKey(MASTER) == false ? + MASTER : // last noe and still no master ofr the cluster + randomFrom(MASTER, DiscoveryNode.Role.DATA, DiscoveryNode.Role.INGEST); final String node; switch (role) { case MASTER: @@ -343,6 +406,59 @@ public class InternalTestClusterTests extends ESTestCase { } finally { cluster.close(); } + } + public void testTwoNodeCluster() throws Exception { + final boolean autoManageMinMasterNodes = randomBoolean(); + NodeConfigurationSource nodeConfigurationSource = new NodeConfigurationSource() { + @Override + public Settings nodeSettings(int nodeOrdinal) { + return Settings.builder().put(NetworkModule.HTTP_ENABLED.getKey(), false) + .put(NodeEnvironment.MAX_LOCAL_STORAGE_NODES_SETTING.getKey(), 2) + .put(NetworkModule.TRANSPORT_TYPE_KEY, MockTcpTransportPlugin.MOCK_TCP_TRANSPORT_NAME) + .build(); + } + + @Override + public Settings transportClientSettings() { + return Settings.builder() + .put(NetworkModule.TRANSPORT_TYPE_KEY, MockTcpTransportPlugin.MOCK_TCP_TRANSPORT_NAME).build(); + } + }; + boolean enableHttpPipelining = randomBoolean(); + String nodePrefix = "test"; + Path baseDir = createTempDir(); + InternalTestCluster cluster = new InternalTestCluster(randomLong(), baseDir, false, autoManageMinMasterNodes, 2, 2, + "test", nodeConfigurationSource, 0, enableHttpPipelining, nodePrefix, + Arrays.asList(MockTcpTransportPlugin.class, TestZenDiscovery.TestPlugin.class), Function.identity()); + try { + cluster.beforeTest(random(), 0.0); + assertMMNinNodeSetting(cluster, 2); + switch (randomInt(2)) { + case 0: + cluster.stopRandomDataNode(); + assertMMNinClusterSetting(cluster, 1); + cluster.startNode(); + assertMMNinClusterSetting(cluster, 2); + assertMMNinNodeSetting(cluster, 2); + break; + case 1: + cluster.rollingRestart(new InternalTestCluster.RestartCallback() { + @Override + public Settings onNodeStopped(String nodeName) throws Exception { + assertMMNinClusterSetting(cluster, 1); + return super.onNodeStopped(nodeName); + } + }); + assertMMNinClusterSetting(cluster, 2); + break; + case 2: + cluster.fullRestart(); + break; + } + assertMMNinNodeSetting(cluster, 2); + } finally { + cluster.close(); + } } } From aa871f839a9cc1a5ad11b76bc974efa21a1bdd2c Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Tue, 15 Nov 2016 15:19:34 +0100 Subject: [PATCH 02/25] [Tests] Do not pass all env vars to sudo (#21562) In #21348 the command executed to run the packaging tests has been changed to "sudo -E bats ...", forcing all environment variables from the vagrant user to be passed to the `sudo` command. This breaks a test on opensuse-13 (the one where it checks that elasticsearch cannot be started when `java` is not found) because all the PATH from the user is passed to the sudo command. This commit restores the previous behavior while allowing only necessary testing environment variables to be passed using a /etc/sudoers.d file. --- Vagrantfile | 10 ++++++++++ .../gradle/vagrant/VagrantTestPlugin.groovy | 2 +- .../test/resources/packaging/tests/20_tar_package.bats | 6 +++++- .../packaging/tests/module_and_plugin_test_cases.bash | 6 +++++- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index 592f0fdc4a5..47b4249bc32 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -280,5 +280,15 @@ export BATS_UTILS=/project/build/bats/utils export BATS_TESTS=/project/build/bats/tests export BATS_ARCHIVES=/project/build/bats/archives VARS + cat \<\ /etc/sudoers.d/elasticsearch_vars +Defaults env_keep += "ZIP" +Defaults env_keep += "TAR" +Defaults env_keep += "RPM" +Defaults env_keep += "DEB" +Defaults env_keep += "BATS" +Defaults env_keep += "BATS_UTILS" +Defaults env_keep += "BATS_TESTS" +Defaults env_keep += "BATS_ARCHIVES" +SUDOERS_VARS SHELL end diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy index 0c16a8972c8..a5bb054a8b6 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy @@ -40,7 +40,7 @@ class VagrantTestPlugin implements Plugin { static List UPGRADE_FROM_ARCHIVES = ['rpm', 'deb'] private static final BATS = 'bats' - private static final String BATS_TEST_COMMAND ="cd \$BATS_ARCHIVES && sudo -E bats --tap \$BATS_TESTS/*.$BATS" + private static final String BATS_TEST_COMMAND ="cd \$BATS_ARCHIVES && sudo bats --tap \$BATS_TESTS/*.$BATS" @Override void apply(Project project) { diff --git a/qa/vagrant/src/test/resources/packaging/tests/20_tar_package.bats b/qa/vagrant/src/test/resources/packaging/tests/20_tar_package.bats index 726cd5468ac..dde2147ea45 100644 --- a/qa/vagrant/src/test/resources/packaging/tests/20_tar_package.bats +++ b/qa/vagrant/src/test/resources/packaging/tests/20_tar_package.bats @@ -88,7 +88,11 @@ setup() { sudo chmod +x $JAVA [ "$status" -eq 1 ] - [[ "$output" == *"Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME"* ]] + local expected="Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME" + [[ "$output" == *"$expected"* ]] || { + echo "Expected error message [$expected] but found: $output" + false + } } ################################## diff --git a/qa/vagrant/src/test/resources/packaging/tests/module_and_plugin_test_cases.bash b/qa/vagrant/src/test/resources/packaging/tests/module_and_plugin_test_cases.bash index 2ff853bc70b..d27953cb49e 100644 --- a/qa/vagrant/src/test/resources/packaging/tests/module_and_plugin_test_cases.bash +++ b/qa/vagrant/src/test/resources/packaging/tests/module_and_plugin_test_cases.bash @@ -176,7 +176,11 @@ fi sudo chmod +x $JAVA [ "$status" -eq 1 ] - [[ "$output" == *"Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME"* ]] + local expected="Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME" + [[ "$output" == *"$expected"* ]] || { + echo "Expected error message [$expected] but found: $output" + false + } } # Note that all of the tests from here to the end of the file expect to be run From df4482fdc8c787ab77497e97e816cf6fa13a1e4f Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Tue, 15 Nov 2016 15:05:23 +0100 Subject: [PATCH 03/25] Do not cache the QueryShardContext in PercolatorFieldMapper: it is cheap to create. --- .../percolator/PercolatorFieldMapper.java | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java b/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java index dd148e8d6d7..383cf959c13 100644 --- a/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java +++ b/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java @@ -234,33 +234,13 @@ public class PercolatorFieldMapper extends FieldMapper { KeywordFieldMapper queryTermsField, KeywordFieldMapper extractionResultField, BinaryFieldMapper queryBuilderField) { super(simpleName, fieldType, defaultFieldType, indexSettings, multiFields, copyTo); - this.queryShardContext = new QueryShardContextSupplierCache(queryShardContext); + this.queryShardContext = queryShardContext; this.queryTermsField = queryTermsField; this.extractionResultField = extractionResultField; this.queryBuilderField = queryBuilderField; this.mapUnmappedFieldAsString = INDEX_MAP_UNMAPPED_FIELDS_AS_STRING_SETTING.get(indexSettings); } - private static class QueryShardContextSupplierCache implements Supplier { - private final Supplier supplier; - private volatile QueryShardContext context; - - QueryShardContextSupplierCache(Supplier supplier) { - this.supplier = supplier; - } - - @Override - public QueryShardContext get() { - QueryShardContext context = this.context; - if (context == null) { - context = this.context = supplier.get(); - } - // return a copy - return new QueryShardContext(context); - } - - } - @Override public FieldMapper updateFieldType(Map fullNameToFieldType) { PercolatorFieldMapper updated = (PercolatorFieldMapper) super.updateFieldType(fullNameToFieldType); From 6db683a4bdbbd587c5118ab858718f80fbb6f68e Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Tue, 15 Nov 2016 16:00:44 +0100 Subject: [PATCH 04/25] Fix recurring doc test failures with the cat API. (#21561) This failure is due to the fact that we sort on store size, which is cached. So it might happen that the store size that is taken into account is not the right one, which makes the indices sorted in the wrong order. This changes the doc example to sort on the number of docs instead. Closes #21062 --- docs/reference/cat/indices.asciidoc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/docs/reference/cat/indices.asciidoc b/docs/reference/cat/indices.asciidoc index fa43e7c696a..2e9e311dda8 100644 --- a/docs/reference/cat/indices.asciidoc +++ b/docs/reference/cat/indices.asciidoc @@ -10,12 +10,7 @@ GET /_cat/indices/twi*?v&s=index -------------------------------------------------- // CONSOLE // TEST[setup:huge_twitter] -// TEST[s/^/POST _flush\n/] // TEST[s/^/PUT twitter2\n{"settings": {"number_of_replicas": 0}}\n/] -// We flush very early here because the index's size is cached and we sort on -// size below. So to get a realistic sort on size we need to flush here or else -// the size is just whatever portion of the index is pushed out of memory -// during test setup which isn't deterministic. Might respond with: @@ -64,11 +59,11 @@ yellow open twitter u8FNjxh8Rfy_awN11oDKYQ 1 1 1200 0 // TESTRESPONSE[s/\d+(\.\d+)?[tgmk]?b/\\d+(\\.\\d+)?[tgmk]?b/] // TESTRESPONSE[s/u8FNjxh8Rfy_awN11oDKYQ/.+/ _cat] -What's my largest index by disk usage not including replicas? +Which index has the largest number of documents? [source,js] -------------------------------------------------- -GET /_cat/indices?v&s=store.size:desc +GET /_cat/indices?v&s=docs.count:desc -------------------------------------------------- // CONSOLE // TEST[continued] From 6cafe688b3f7f6a0a6493d8139b1bd1947d11bac Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Tue, 15 Nov 2016 17:42:57 +0100 Subject: [PATCH 05/25] [TEST] Ensure file permission for /etc/sudoers.d/elasticsearch_vars Ubuntu 12.04 checks the file permission for /etc/sudoers.d/elasticsearch_vars is mode 0440. This commit adds a `chmod` before the file is used by the `sudo` command. --- Vagrantfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Vagrantfile b/Vagrantfile index 47b4249bc32..806d39cc160 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -290,5 +290,6 @@ Defaults env_keep += "BATS_UTILS" Defaults env_keep += "BATS_TESTS" Defaults env_keep += "BATS_ARCHIVES" SUDOERS_VARS + chmod 0440 /etc/sudoers.d/elasticsearch_vars SHELL end From 7dcff27aea501754bcea971d5ef2fb2219032664 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Tue, 15 Nov 2016 11:45:54 -0500 Subject: [PATCH 06/25] Update docs for scripted metric agg Now that the default language is painless the examples didn't work at all. This fixes them. Closes #21536 --- docs/build.gradle | 37 ++++++ .../scripted-metric-aggregation.asciidoc | 117 ++++++++++-------- .../config/scripts/my_combine_script.painless | 5 + .../config/scripts/my_init_script.painless | 1 + .../config/scripts/my_map_script.painless | 1 + .../config/scripts/my_reduce_script.painless | 5 + 6 files changed, 112 insertions(+), 54 deletions(-) create mode 100644 docs/src/test/cluster/config/scripts/my_combine_script.painless create mode 100644 docs/src/test/cluster/config/scripts/my_init_script.painless create mode 100644 docs/src/test/cluster/config/scripts/my_map_script.painless create mode 100644 docs/src/test/cluster/config/scripts/my_reduce_script.painless diff --git a/docs/build.gradle b/docs/build.gradle index 3c305fd3910..ec9800bab0f 100644 --- a/docs/build.gradle +++ b/docs/build.gradle @@ -171,6 +171,10 @@ integTest { } configFile 'scripts/my_script.js' configFile 'scripts/my_script.py' + configFile 'scripts/my_init_script.painless' + configFile 'scripts/my_map_script.painless' + configFile 'scripts/my_combine_script.painless' + configFile 'scripts/my_reduce_script.painless' configFile 'userdict_ja.txt' configFile 'KeywordTokenizer.rbbi' // Whitelist reindexing from the local node so we can test it. @@ -249,6 +253,39 @@ buildRestTests.setups['host'] = ''' - set: {nodes.$master.http.publish_address: host} ''' +// Used by scripted metric docs +buildRestTests.setups['ledger'] = ''' + - do: + indices.create: + index: ledger + body: + settings: + number_of_shards: 2 + number_of_replicas: 1 + mappings: + sale: + properties: + type: + type: keyword + amount: + type: double + - do: + bulk: + index: ledger + type: item + refresh: true + body: | + {"index":{}} + {"date": "2015/01/01 00:00:00", "amount": 200, "type": "sale", "description": "something"} + {"index":{}} + {"date": "2015/01/01 00:00:00", "amount": 10, "type": "expense", "decription": "another thing"} + {"index":{}} + {"date": "2015/01/01 00:00:00", "amount": 150, "type": "sale", "description": "blah"} + {"index":{}} + {"date": "2015/01/01 00:00:00", "amount": 50, "type": "expense", "description": "cost of blah"} + {"index":{}} + {"date": "2015/01/01 00:00:00", "amount": 50, "type": "expense", "description": "advertisement"}''' + // Used by pipeline aggregation docs buildRestTests.setups['sales'] = ''' - do: diff --git a/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc b/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc index 3c3e9b8d13d..2a629a88d64 100644 --- a/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc +++ b/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc @@ -9,6 +9,7 @@ Example: [source,js] -------------------------------------------------- +POST ledger/_search?size=0 { "query" : { "match_all" : {} @@ -16,15 +17,17 @@ Example: "aggs": { "profit": { "scripted_metric": { - "init_script" : "_agg['transactions'] = []", - "map_script" : "if (doc['type'].value == \"sale\") { _agg.transactions.add(doc['amount'].value) } else { _agg.transactions.add(-1 * doc['amount'].value) }", <1> - "combine_script" : "profit = 0; for (t in _agg.transactions) { profit += t }; return profit", - "reduce_script" : "profit = 0; for (a in _aggs) { profit += a }; return profit" + "init_script" : "params._agg.transactions = []", + "map_script" : "params._agg.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)", <1> + "combine_script" : "double profit = 0; for (t in params._agg.transactions) { profit += t } return profit", + "reduce_script" : "double profit = 0; for (a in params._aggs) { profit += a } return profit" } } } } -------------------------------------------------- +// CONSOLE +// TEST[setup:ledger] <1> `map_script` is the only required parameter @@ -35,24 +38,24 @@ The response for the above aggregation: [source,js] -------------------------------------------------- { + "took": 218, ... - "aggregations": { "profit": { - "value": 170 + "value": 240.0 } } } -------------------------------------------------- +// TESTRESPONSE[s/"took": 218/"took": $body.took/] +// TESTRESPONSE[s/\.\.\./"_shards": $body._shards, "hits": $body.hits, "timed_out": false,/] The above example can also be specified using file scripts as follows: [source,js] -------------------------------------------------- +POST ledger/_search?size=0 { - "query" : { - "match_all" : {} - }, "aggs": { "profit": { "scripted_metric": { @@ -66,18 +69,42 @@ The above example can also be specified using file scripts as follows: "file": "my_combine_script" }, "params": { - "field": "amount" <1> + "field": "amount", <1> + "_agg": {} <2> }, "reduce_script" : { "file": "my_reduce_script" - }, + } } } } } -------------------------------------------------- +// CONSOLE +// TEST[setup:ledger] -<1> script parameters for init, map and combine scripts must be specified in a global `params` object so that it can be share between the scripts +<1> script parameters for `init`, `map` and `combine` scripts must be specified +in a global `params` object so that it can be share between the scripts. +<2> if you specify script parameters then you must specify `"_agg": {}`. + +//// +Verify this response as well but in a hidden block. + +[source,js] +-------------------------------------------------- +{ + "took": 218, + ... + "aggregations": { + "profit": { + "value": 240.0 + } + } +} +-------------------------------------------------- +// TESTRESPONSE[s/"took": 218/"took": $body.took/] +// TESTRESPONSE[s/\.\.\./"_shards": $body._shards, "hits": $body.hits, "timed_out": false,/] +//// For more details on specifying scripts see <>. @@ -88,7 +115,7 @@ Whilst and valid script object can be used within a single script. the scripts m * primitive types * String * Map (containing only keys and values of the types listed here) -* Array (containing elements of only the types listed here) +* Array (containing elements of only the types listed here) ==== Scope of scripts @@ -98,24 +125,24 @@ init_script:: Executed prior to any collection of documents. Allows the ag + In the above example, the `init_script` creates an array `transactions` in the `_agg` object. -map_script:: Executed once per document collected. This is the only required script. If no combine_script is specified, the resulting state +map_script:: Executed once per document collected. This is the only required script. If no combine_script is specified, the resulting state needs to be stored in an object named `_agg`. + -In the above example, the `map_script` checks the value of the type field. If the value is 'sale' the value of the amount field -is added to the transactions array. If the value of the type field is not 'sale' the negated value of the amount field is added +In the above example, the `map_script` checks the value of the type field. If the value is 'sale' the value of the amount field +is added to the transactions array. If the value of the type field is not 'sale' the negated value of the amount field is added to transactions. -combine_script:: Executed once on each shard after document collection is complete. Allows the aggregation to consolidate the state returned from +combine_script:: Executed once on each shard after document collection is complete. Allows the aggregation to consolidate the state returned from each shard. If a combine_script is not provided the combine phase will return the aggregation variable. + -In the above example, the `combine_script` iterates through all the stored transactions, summing the values in the `profit` variable +In the above example, the `combine_script` iterates through all the stored transactions, summing the values in the `profit` variable and finally returns `profit`. -reduce_script:: Executed once on the coordinating node after all shards have returned their results. The script is provided with access to a - variable `_aggs` which is an array of the result of the combine_script on each shard. If a reduce_script is not provided +reduce_script:: Executed once on the coordinating node after all shards have returned their results. The script is provided with access to a + variable `_aggs` which is an array of the result of the combine_script on each shard. If a reduce_script is not provided the reduce phase will return the `_aggs` variable. + -In the above example, the `reduce_script` iterates through the `profit` returned by each shard summing the values before returning the +In the above example, the `reduce_script` iterates through the `profit` returned by each shard summing the values before returning the final combined profit which will be returned in the response of the aggregation. ==== Worked Example @@ -124,36 +151,19 @@ Imagine a situation where you index the following documents into and index with [source,js] -------------------------------------------------- -$ curl -XPUT 'http://localhost:9200/transactions/stock/1' -d ' -{ - "type": "sale", - "amount": 80 -} -' - -$ curl -XPUT 'http://localhost:9200/transactions/stock/2' -d ' -{ - "type": "cost", - "amount": 10 -} -' - -$ curl -XPUT 'http://localhost:9200/transactions/stock/3' -d ' -{ - "type": "cost", - "amount": 30 -} -' - -$ curl -XPUT 'http://localhost:9200/transactions/stock/4' -d ' -{ - "type": "sale", - "amount": 130 -} -' +PUT /transactions/stock/_bulk?refresh +{"index":{"_id":1}} +{"type": "sale","amount": 80} +{"index":{"_id":2}} +{"type": "cost","amount": 10} +{"index":{"_id":2}} +{"type": "cost","amount": 30} +{"index":{"_id":2}} +{"type": "sale","amount": 130} -------------------------------------------------- +// CONSOLE -Lets say that documents 1 and 3 end up on shard A and documents 2 and 4 end up on shard B. The following is a breakdown of what the aggregation result is +Lets say that documents 1 and 3 end up on shard A and documents 2 and 4 end up on shard B. The following is a breakdown of what the aggregation result is at each stage of the example above. ===== Before init_script @@ -221,7 +231,7 @@ Shard B:: ===== After combine_script -The combine_script is executed on each shard after document collection is complete and reduces all the transactions down to a single profit figure for each +The combine_script is executed on each shard after document collection is complete and reduces all the transactions down to a single profit figure for each shard (by summing the values in the transactions array) which is passed back to the coordinating node: Shard A:: 50 @@ -239,7 +249,7 @@ The reduce_script receives an `_aggs` array containing the result of the combine ] -------------------------------------------------- -It reduces the responses for the shards down to a final overall profit figure (by summing the values) and returns this as the result of the aggregation to +It reduces the responses for the shards down to a final overall profit figure (by summing the values) and returns this as the result of the aggregation to produce the response: [source,js] @@ -258,8 +268,8 @@ produce the response: ==== Other Parameters [horizontal] -params:: Optional. An object whose contents will be passed as variables to the `init_script`, `map_script` and `combine_script`. This can be - useful to allow the user to control the behavior of the aggregation and for storing state between the scripts. If this is not specified, +params:: Optional. An object whose contents will be passed as variables to the `init_script`, `map_script` and `combine_script`. This can be + useful to allow the user to control the behavior of the aggregation and for storing state between the scripts. If this is not specified, the default is the equivalent of providing: + [source,js] @@ -268,4 +278,3 @@ params:: Optional. An object whose contents will be passed as variable "_agg" : {} } -------------------------------------------------- - diff --git a/docs/src/test/cluster/config/scripts/my_combine_script.painless b/docs/src/test/cluster/config/scripts/my_combine_script.painless new file mode 100644 index 00000000000..106ef08d91f --- /dev/null +++ b/docs/src/test/cluster/config/scripts/my_combine_script.painless @@ -0,0 +1,5 @@ +double profit = 0; +for (t in params._agg.transactions) { + profit += t +} +return profit diff --git a/docs/src/test/cluster/config/scripts/my_init_script.painless b/docs/src/test/cluster/config/scripts/my_init_script.painless new file mode 100644 index 00000000000..fb6aa11723c --- /dev/null +++ b/docs/src/test/cluster/config/scripts/my_init_script.painless @@ -0,0 +1 @@ +params._agg.transactions = [] diff --git a/docs/src/test/cluster/config/scripts/my_map_script.painless b/docs/src/test/cluster/config/scripts/my_map_script.painless new file mode 100644 index 00000000000..f4700482d55 --- /dev/null +++ b/docs/src/test/cluster/config/scripts/my_map_script.painless @@ -0,0 +1 @@ +params._agg.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value) diff --git a/docs/src/test/cluster/config/scripts/my_reduce_script.painless b/docs/src/test/cluster/config/scripts/my_reduce_script.painless new file mode 100644 index 00000000000..ca4f67ca2db --- /dev/null +++ b/docs/src/test/cluster/config/scripts/my_reduce_script.painless @@ -0,0 +1,5 @@ +double profit = 0; +for (a in params._aggs) { + profit += a +} +return profit From 568a7ea5f197dc3f7396280a4bb0a4d5fcda7868 Mon Sep 17 00:00:00 2001 From: Lee Hinman Date: Tue, 15 Nov 2016 09:57:26 -0700 Subject: [PATCH 07/25] Fix incorrect instructions for disabling deprecation logging (#21569) We log deprecation events at "WARN", so setting it to `info` means the events are still logged. It must be set to `error` in order to disable the logging. --- docs/reference/setup/configuration.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/setup/configuration.asciidoc b/docs/reference/setup/configuration.asciidoc index 8db4f6bae59..ac8855bf3d8 100644 --- a/docs/reference/setup/configuration.asciidoc +++ b/docs/reference/setup/configuration.asciidoc @@ -179,4 +179,4 @@ logs to roll and compress after 1 GB, and to preserve a maximum of five log files (four rolled logs, and the active log). You can disable it in the `config/log4j2.properties` file by setting the deprecation -log level to `info`. +log level to `error`. From f5ac0e507661ec127afa07ed8dd34da50b2e4d5d Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Tue, 15 Nov 2016 12:17:26 -0500 Subject: [PATCH 08/25] Remove lenient stats parsing Today when parsing a stats request, Elasticsearch silently ignores incorrect metrics. This commit removes lenient parsing of stats requests for the nodes stats and indices stats APIs. Relates #21417 --- .../elasticsearch/rest/BaseRestHandler.java | 83 +++++----- .../admin/cluster/RestNodesInfoAction.java | 2 +- .../admin/cluster/RestNodesStatsAction.java | 106 ++++++++++--- .../admin/indices/RestIndicesStatsAction.java | 67 +++++--- .../cluster/RestNodesStatsActionTests.java | 144 ++++++++++++++++++ .../indices/RestIndicesStatsActionTests.java | 83 ++++++++++ docs/reference/cluster/nodes-stats.asciidoc | 43 ++++-- docs/reference/indices/flush.asciidoc | 2 +- .../test/indices.stats/10_index.yaml | 14 ++ .../test/nodes.stats/10_basic.yaml | 14 ++ 10 files changed, 472 insertions(+), 86 deletions(-) create mode 100644 core/src/test/java/org/elasticsearch/rest/action/admin/cluster/RestNodesStatsActionTests.java create mode 100644 core/src/test/java/org/elasticsearch/rest/action/admin/indices/RestIndicesStatsActionTests.java diff --git a/core/src/main/java/org/elasticsearch/rest/BaseRestHandler.java b/core/src/main/java/org/elasticsearch/rest/BaseRestHandler.java index 3bb6c6773b9..f1804ee01b1 100644 --- a/core/src/main/java/org/elasticsearch/rest/BaseRestHandler.java +++ b/core/src/main/java/org/elasticsearch/rest/BaseRestHandler.java @@ -71,49 +71,58 @@ public abstract class BaseRestHandler extends AbstractComponent implements RestH request.unconsumedParams().stream().filter(p -> !responseParams().contains(p)).collect(Collectors.toCollection(TreeSet::new)); // validate the non-response params - if (unconsumedParams.isEmpty() == false) { - String message = String.format( - Locale.ROOT, - "request [%s] contains unrecognized parameter%s: ", - request.path(), - unconsumedParams.size() > 1 ? "s" : ""); - boolean first = true; - for (final String unconsumedParam : unconsumedParams) { - final LevensteinDistance ld = new LevensteinDistance(); - final List> scoredParams = new ArrayList<>(); - final Set candidateParams = new HashSet<>(); - candidateParams.addAll(request.consumedParams()); - candidateParams.addAll(responseParams()); - for (final String candidateParam : candidateParams) { - final float distance = ld.getDistance(unconsumedParam, candidateParam); - if (distance > 0.5f) { - scoredParams.add(new Tuple<>(distance, candidateParam)); - } - } - CollectionUtil.timSort(scoredParams, (a, b) -> { - // sort by distance in reverse order, then parameter name for equal distances - int compare = a.v1().compareTo(b.v1()); - if (compare != 0) return -compare; - else return a.v2().compareTo(b.v2()); - }); - if (first == false) { - message += ", "; - } - message += "[" + unconsumedParam + "]"; - final List keys = scoredParams.stream().map(Tuple::v2).collect(Collectors.toList()); - if (keys.isEmpty() == false) { - message += " -> did you mean " + (keys.size() == 1 ? "[" + keys.get(0) + "]": "any of " + keys.toString()) + "?"; - } - first = false; - } - - throw new IllegalArgumentException(message); + if (!unconsumedParams.isEmpty()) { + final Set candidateParams = new HashSet<>(); + candidateParams.addAll(request.consumedParams()); + candidateParams.addAll(responseParams()); + throw new IllegalArgumentException(unrecognized(request, unconsumedParams, candidateParams, "parameter")); } // execute the action action.accept(channel); } + protected final String unrecognized( + final RestRequest request, + final Set invalids, + final Set candidates, + final String detail) { + String message = String.format( + Locale.ROOT, + "request [%s] contains unrecognized %s%s: ", + request.path(), + detail, + invalids.size() > 1 ? "s" : ""); + boolean first = true; + for (final String invalid : invalids) { + final LevensteinDistance ld = new LevensteinDistance(); + final List> scoredParams = new ArrayList<>(); + for (final String candidate : candidates) { + final float distance = ld.getDistance(invalid, candidate); + if (distance > 0.5f) { + scoredParams.add(new Tuple<>(distance, candidate)); + } + } + CollectionUtil.timSort(scoredParams, (a, b) -> { + // sort by distance in reverse order, then parameter name for equal distances + int compare = a.v1().compareTo(b.v1()); + if (compare != 0) return -compare; + else return a.v2().compareTo(b.v2()); + }); + if (first == false) { + message += ", "; + } + message += "[" + invalid + "]"; + final List keys = scoredParams.stream().map(Tuple::v2).collect(Collectors.toList()); + if (keys.isEmpty() == false) { + message += " -> did you mean " + (keys.size() == 1 ? "[" + keys.get(0) + "]" : "any of " + keys.toString()) + "?"; + } + first = false; + } + + return message; + } + /** * REST requests are handled by preparing a channel consumer that represents the execution of * the request against a channel. diff --git a/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestNodesInfoAction.java b/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestNodesInfoAction.java index 40cfc6372a3..d4da4fc931d 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestNodesInfoAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestNodesInfoAction.java @@ -55,7 +55,7 @@ public class RestNodesInfoAction extends BaseRestHandler { public RestNodesInfoAction(Settings settings, RestController controller, SettingsFilter settingsFilter) { super(settings); controller.registerHandler(GET, "/_nodes", this); - // this endpoint is used for metrics, not for nodeIds, like /_nodes/fs + // this endpoint is used for metrics, not for node IDs, like /_nodes/fs controller.registerHandler(GET, "/_nodes/{nodeId}", this); controller.registerHandler(GET, "/_nodes/{nodeId}/{metrics}", this); // added this endpoint to be aligned with stats diff --git a/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestNodesStatsAction.java b/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestNodesStatsAction.java index 917f5b2c5b1..93094844025 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestNodesStatsAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestNodesStatsAction.java @@ -33,7 +33,13 @@ import org.elasticsearch.rest.action.RestActions.NodesResponseRestListener; import java.io.IOException; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; import java.util.Set; +import java.util.TreeSet; +import java.util.function.Consumer; import static org.elasticsearch.rest.RestRequest.Method.GET; @@ -48,9 +54,38 @@ public class RestNodesStatsAction extends BaseRestHandler { controller.registerHandler(GET, "/_nodes/stats/{metric}", this); controller.registerHandler(GET, "/_nodes/{nodeId}/stats/{metric}", this); - controller.registerHandler(GET, "/_nodes/stats/{metric}/{indexMetric}", this); + controller.registerHandler(GET, "/_nodes/stats/{metric}/{index_metric}", this); - controller.registerHandler(GET, "/_nodes/{nodeId}/stats/{metric}/{indexMetric}", this); + controller.registerHandler(GET, "/_nodes/{nodeId}/stats/{metric}/{index_metric}", this); + } + + static final Map> METRICS; + + static { + final Map> metrics = new HashMap<>(); + metrics.put("os", r -> r.os(true)); + metrics.put("jvm", r -> r.jvm(true)); + metrics.put("thread_pool", r -> r.threadPool(true)); + metrics.put("fs", r -> r.fs(true)); + metrics.put("transport", r -> r.transport(true)); + metrics.put("http", r -> r.http(true)); + metrics.put("indices", r -> r.indices(true)); + metrics.put("process", r -> r.process(true)); + metrics.put("breaker", r -> r.breaker(true)); + metrics.put("script", r -> r.script(true)); + metrics.put("discovery", r -> r.discovery(true)); + metrics.put("ingest", r -> r.ingest(true)); + METRICS = Collections.unmodifiableMap(metrics); + } + + static final Map> FLAGS; + + static { + final Map> flags = new HashMap<>(); + for (final Flag flag : CommonStatsFlags.Flag.values()) { + flags.put(flag.getRestName(), f -> f.set(flag, true)); + } + FLAGS = Collections.unmodifiableMap(flags); } @Override @@ -62,35 +97,72 @@ public class RestNodesStatsAction extends BaseRestHandler { nodesStatsRequest.timeout(request.param("timeout")); if (metrics.size() == 1 && metrics.contains("_all")) { + if (request.hasParam("index_metric")) { + throw new IllegalArgumentException( + String.format( + Locale.ROOT, + "request [%s] contains index metrics [%s] but all stats requested", + request.path(), + request.param("index_metric"))); + } nodesStatsRequest.all(); nodesStatsRequest.indices(CommonStatsFlags.ALL); + } else if (metrics.contains("_all")) { + throw new IllegalArgumentException( + String.format(Locale.ROOT, + "request [%s] contains _all and individual metrics [%s]", + request.path(), + request.param("metric"))); } else { nodesStatsRequest.clear(); - nodesStatsRequest.os(metrics.contains("os")); - nodesStatsRequest.jvm(metrics.contains("jvm")); - nodesStatsRequest.threadPool(metrics.contains("thread_pool")); - nodesStatsRequest.fs(metrics.contains("fs")); - nodesStatsRequest.transport(metrics.contains("transport")); - nodesStatsRequest.http(metrics.contains("http")); - nodesStatsRequest.indices(metrics.contains("indices")); - nodesStatsRequest.process(metrics.contains("process")); - nodesStatsRequest.breaker(metrics.contains("breaker")); - nodesStatsRequest.script(metrics.contains("script")); - nodesStatsRequest.discovery(metrics.contains("discovery")); - nodesStatsRequest.ingest(metrics.contains("ingest")); + + // use a sorted set so the unrecognized parameters appear in a reliable sorted order + final Set invalidMetrics = new TreeSet<>(); + for (final String metric : metrics) { + final Consumer handler = METRICS.get(metric); + if (handler != null) { + handler.accept(nodesStatsRequest); + } else { + invalidMetrics.add(metric); + } + } + + if (!invalidMetrics.isEmpty()) { + throw new IllegalArgumentException(unrecognized(request, invalidMetrics, METRICS.keySet(), "metric")); + } // check for index specific metrics if (metrics.contains("indices")) { - Set indexMetrics = Strings.splitStringByCommaToSet(request.param("indexMetric", "_all")); + Set indexMetrics = Strings.splitStringByCommaToSet(request.param("index_metric", "_all")); if (indexMetrics.size() == 1 && indexMetrics.contains("_all")) { nodesStatsRequest.indices(CommonStatsFlags.ALL); } else { CommonStatsFlags flags = new CommonStatsFlags(); - for (Flag flag : CommonStatsFlags.Flag.values()) { - flags.set(flag, indexMetrics.contains(flag.getRestName())); + flags.clear(); + // use a sorted set so the unrecognized parameters appear in a reliable sorted order + final Set invalidIndexMetrics = new TreeSet<>(); + for (final String indexMetric : indexMetrics) { + final Consumer handler = FLAGS.get(indexMetric); + if (handler != null) { + handler.accept(flags); + } else { + invalidIndexMetrics.add(indexMetric); + } } + + if (!invalidIndexMetrics.isEmpty()) { + throw new IllegalArgumentException(unrecognized(request, invalidIndexMetrics, FLAGS.keySet(), "index metric")); + } + nodesStatsRequest.indices(flags); } + } else if (request.hasParam("index_metric")) { + throw new IllegalArgumentException( + String.format( + Locale.ROOT, + "request [%s] contains index metrics [%s] but indices stats not requested", + request.path(), + request.param("index_metric"))); } } diff --git a/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestIndicesStatsAction.java b/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestIndicesStatsAction.java index e7336225c5e..041a15b4119 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestIndicesStatsAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestIndicesStatsAction.java @@ -36,7 +36,13 @@ import org.elasticsearch.rest.action.RestBuilderListener; import java.io.IOException; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; import java.util.Set; +import java.util.TreeSet; +import java.util.function.Consumer; import static org.elasticsearch.rest.RestRequest.Method.GET; import static org.elasticsearch.rest.RestStatus.OK; @@ -49,11 +55,34 @@ public class RestIndicesStatsAction extends BaseRestHandler { super(settings); controller.registerHandler(GET, "/_stats", this); controller.registerHandler(GET, "/_stats/{metric}", this); - controller.registerHandler(GET, "/_stats/{metric}/{indexMetric}", this); controller.registerHandler(GET, "/{index}/_stats", this); controller.registerHandler(GET, "/{index}/_stats/{metric}", this); } + static Map> METRICS; + + static { + final Map> metrics = new HashMap<>(); + metrics.put("docs", r -> r.docs(true)); + metrics.put("store", r -> r.store(true)); + metrics.put("indexing", r -> r.indexing(true)); + metrics.put("search", r -> r.search(true)); + metrics.put("suggest", r -> r.search(true)); + metrics.put("get", r -> r.get(true)); + metrics.put("merge", r -> r.merge(true)); + metrics.put("refresh", r -> r.refresh(true)); + metrics.put("flush", r -> r.flush(true)); + metrics.put("warmer", r -> r.warmer(true)); + metrics.put("query_cache", r -> r.queryCache(true)); + metrics.put("segments", r -> r.segments(true)); + metrics.put("fielddata", r -> r.fieldData(true)); + metrics.put("completion", r -> r.completion(true)); + metrics.put("request_cache", r -> r.requestCache(true)); + metrics.put("recovery", r -> r.recovery(true)); + metrics.put("translog", r -> r.translog(true)); + METRICS = Collections.unmodifiableMap(metrics); + } + @Override public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { IndicesStatsRequest indicesStatsRequest = new IndicesStatsRequest(); @@ -65,24 +94,28 @@ public class RestIndicesStatsAction extends BaseRestHandler { // short cut, if no metrics have been specified in URI if (metrics.size() == 1 && metrics.contains("_all")) { indicesStatsRequest.all(); + } else if (metrics.contains("_all")) { + throw new IllegalArgumentException( + String.format(Locale.ROOT, + "request [%s] contains _all and individual metrics [%s]", + request.path(), + request.param("metric"))); } else { indicesStatsRequest.clear(); - indicesStatsRequest.docs(metrics.contains("docs")); - indicesStatsRequest.store(metrics.contains("store")); - indicesStatsRequest.indexing(metrics.contains("indexing")); - indicesStatsRequest.search(metrics.contains("search") || metrics.contains("suggest")); - indicesStatsRequest.get(metrics.contains("get")); - indicesStatsRequest.merge(metrics.contains("merge")); - indicesStatsRequest.refresh(metrics.contains("refresh")); - indicesStatsRequest.flush(metrics.contains("flush")); - indicesStatsRequest.warmer(metrics.contains("warmer")); - indicesStatsRequest.queryCache(metrics.contains("query_cache")); - indicesStatsRequest.segments(metrics.contains("segments")); - indicesStatsRequest.fieldData(metrics.contains("fielddata")); - indicesStatsRequest.completion(metrics.contains("completion")); - indicesStatsRequest.requestCache(metrics.contains("request_cache")); - indicesStatsRequest.recovery(metrics.contains("recovery")); - indicesStatsRequest.translog(metrics.contains("translog")); + // use a sorted set so the unrecognized parameters appear in a reliable sorted order + final Set invalidMetrics = new TreeSet<>(); + for (final String metric : metrics) { + final Consumer consumer = METRICS.get(metric); + if (consumer != null) { + consumer.accept(indicesStatsRequest); + } else { + invalidMetrics.add(metric); + } + } + + if (!invalidMetrics.isEmpty()) { + throw new IllegalArgumentException(unrecognized(request, invalidMetrics, METRICS.keySet(), "metric")); + } } if (request.hasParam("groups")) { diff --git a/core/src/test/java/org/elasticsearch/rest/action/admin/cluster/RestNodesStatsActionTests.java b/core/src/test/java/org/elasticsearch/rest/action/admin/cluster/RestNodesStatsActionTests.java new file mode 100644 index 00000000000..c3764ff8959 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/rest/action/admin/cluster/RestNodesStatsActionTests.java @@ -0,0 +1,144 @@ +/* + * 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.rest.action.admin.cluster; + +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.rest.RestController; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.rest.FakeRestRequest; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.object.HasToString.hasToString; +import static org.mockito.Mockito.mock; + +public class RestNodesStatsActionTests extends ESTestCase { + + private RestNodesStatsAction action; + + @Override + public void setUp() throws Exception { + super.setUp(); + action = new RestNodesStatsAction(Settings.EMPTY, new RestController(Settings.EMPTY, Collections.emptySet())); + } + + public void testUnrecognizedMetric() throws IOException { + final HashMap params = new HashMap<>(); + final String metric = randomAsciiOfLength(64); + params.put("metric", metric); + final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build(); + final IllegalArgumentException e = expectThrows( + IllegalArgumentException.class, + () -> action.prepareRequest(request, mock(NodeClient.class))); + assertThat(e, hasToString(containsString("request [/_nodes/stats] contains unrecognized metric: [" + metric + "]"))); + } + + public void testUnrecognizedMetricDidYouMean() throws IOException { + final HashMap params = new HashMap<>(); + params.put("metric", "os,transprot,unrecognized"); + final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build(); + final IllegalArgumentException e = expectThrows( + IllegalArgumentException.class, + () -> action.prepareRequest(request, mock(NodeClient.class))); + assertThat( + e, + hasToString( + containsString( + "request [/_nodes/stats] contains unrecognized metrics: [transprot] -> did you mean [transport]?, [unrecognized]"))); + } + + public void testAllRequestWithOtherMetrics() throws IOException { + final HashMap params = new HashMap<>(); + final String metric = randomSubsetOf(1, RestNodesStatsAction.METRICS.keySet()).get(0); + params.put("metric", "_all," + metric); + final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build(); + final IllegalArgumentException e = expectThrows( + IllegalArgumentException.class, + () -> action.prepareRequest(request, mock(NodeClient.class))); + assertThat(e, hasToString(containsString("request [/_nodes/stats] contains _all and individual metrics [_all," + metric + "]"))); + } + + public void testUnrecognizedIndexMetric() { + final HashMap params = new HashMap<>(); + params.put("metric", "indices"); + final String indexMetric = randomAsciiOfLength(64); + params.put("index_metric", indexMetric); + final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build(); + final IllegalArgumentException e = expectThrows( + IllegalArgumentException.class, + () -> action.prepareRequest(request, mock(NodeClient.class))); + assertThat(e, hasToString(containsString("request [/_nodes/stats] contains unrecognized index metric: [" + indexMetric + "]"))); + } + + public void testUnrecognizedIndexMetricDidYouMean() { + final HashMap params = new HashMap<>(); + params.put("metric", "indices"); + params.put("index_metric", "indexing,stroe,unrecognized"); + final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build(); + final IllegalArgumentException e = expectThrows( + IllegalArgumentException.class, + () -> action.prepareRequest(request, mock(NodeClient.class))); + assertThat( + e, + hasToString( + containsString( + "request [/_nodes/stats] contains unrecognized index metrics: [stroe] -> did you mean [store]?, [unrecognized]"))); + } + + public void testIndexMetricsRequestWithoutIndicesMetric() throws IOException { + final HashMap params = new HashMap<>(); + final Set metrics = new HashSet<>(RestNodesStatsAction.METRICS.keySet()); + metrics.remove("indices"); + params.put("metric", randomSubsetOf(1, metrics).get(0)); + final String indexMetric = randomSubsetOf(1, RestNodesStatsAction.FLAGS.keySet()).get(0); + params.put("index_metric", indexMetric); + final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build(); + final IllegalArgumentException e = expectThrows( + IllegalArgumentException.class, + () -> action.prepareRequest(request, mock(NodeClient.class))); + assertThat( + e, + hasToString( + containsString("request [/_nodes/stats] contains index metrics [" + indexMetric + "] but indices stats not requested"))); + } + + public void testIndexMetricsRequestOnAllRequest() throws IOException { + final HashMap params = new HashMap<>(); + params.put("metric", "_all"); + final String indexMetric = randomSubsetOf(1, RestNodesStatsAction.FLAGS.keySet()).get(0); + params.put("index_metric", indexMetric); + final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build(); + final IllegalArgumentException e = expectThrows( + IllegalArgumentException.class, + () -> action.prepareRequest(request, mock(NodeClient.class))); + assertThat( + e, + hasToString( + containsString("request [/_nodes/stats] contains index metrics [" + indexMetric + "] but all stats requested"))); + } + +} diff --git a/core/src/test/java/org/elasticsearch/rest/action/admin/indices/RestIndicesStatsActionTests.java b/core/src/test/java/org/elasticsearch/rest/action/admin/indices/RestIndicesStatsActionTests.java new file mode 100644 index 00000000000..13ef39ef4df --- /dev/null +++ b/core/src/test/java/org/elasticsearch/rest/action/admin/indices/RestIndicesStatsActionTests.java @@ -0,0 +1,83 @@ +/* + * 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.rest.action.admin.indices; + +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.rest.RestController; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.rest.FakeRestRequest; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.object.HasToString.hasToString; +import static org.mockito.Mockito.mock; + +public class RestIndicesStatsActionTests extends ESTestCase { + + private RestIndicesStatsAction action; + + @Override + public void setUp() throws Exception { + super.setUp(); + action = new RestIndicesStatsAction(Settings.EMPTY, new RestController(Settings.EMPTY, Collections.emptySet())); + } + + public void testUnrecognizedMetric() throws IOException { + final HashMap params = new HashMap<>(); + final String metric = randomAsciiOfLength(64); + params.put("metric", metric); + final RestRequest request = new FakeRestRequest.Builder().withPath("/_stats").withParams(params).build(); + final IllegalArgumentException e = expectThrows( + IllegalArgumentException.class, + () -> action.prepareRequest(request, mock(NodeClient.class))); + assertThat(e, hasToString(containsString("request [/_stats] contains unrecognized metric: [" + metric + "]"))); + } + + public void testUnrecognizedMetricDidYouMean() throws IOException { + final HashMap params = new HashMap<>(); + params.put("metric", "request_cache,fieldata,unrecognized"); + final RestRequest request = new FakeRestRequest.Builder().withPath("/_stats").withParams(params).build(); + final IllegalArgumentException e = expectThrows( + IllegalArgumentException.class, + () -> action.prepareRequest(request, mock(NodeClient.class))); + assertThat( + e, + hasToString( + containsString( + "request [/_stats] contains unrecognized metrics: [fieldata] -> did you mean [fielddata]?, [unrecognized]"))); + } + + public void testAllRequestWithOtherMetrics() throws IOException { + final HashMap params = new HashMap<>(); + final String metric = randomSubsetOf(1, RestIndicesStatsAction.METRICS.keySet()).get(0); + params.put("metric", "_all," + metric); + final RestRequest request = new FakeRestRequest.Builder().withPath("/_stats").withParams(params).build(); + final IllegalArgumentException e = expectThrows( + IllegalArgumentException.class, + () -> action.prepareRequest(request, mock(NodeClient.class))); + assertThat(e, hasToString(containsString("request [/_stats] contains _all and individual metrics [_all," + metric + "]"))); + } + +} diff --git a/docs/reference/cluster/nodes-stats.asciidoc b/docs/reference/cluster/nodes-stats.asciidoc index 215cf8b8d7a..493d5db5613 100644 --- a/docs/reference/cluster/nodes-stats.asciidoc +++ b/docs/reference/cluster/nodes-stats.asciidoc @@ -65,12 +65,11 @@ of `indices`, `os`, `process`, `jvm`, `transport`, `http`, [source,js] -------------------------------------------------- -# return indices and os -curl -XGET 'http://localhost:9200/_nodes/stats/os' +# return just indices +curl -XGET 'http://localhost:9200/_nodes/stats/indices' # return just os and process curl -XGET 'http://localhost:9200/_nodes/stats/os,process' -# specific type endpoint -curl -XGET 'http://localhost:9200/_nodes/stats/process' +# return just process for node with IP address 10.0.0.1 curl -XGET 'http://localhost:9200/_nodes/10.0.0.1/stats/process' -------------------------------------------------- @@ -280,27 +279,45 @@ the current running process: `process.mem.total_virtual_in_bytes`:: Size in bytes of virtual memory that is guaranteed to be available to the running process - [float] -[[field-data]] -=== Field data statistics +[[indices-stats]] +=== Indices statistics -You can get information about field data memory usage on node -level or on index level. +You can get information about indices stats on node level or on index level. [source,js] -------------------------------------------------- -# Node Stats -curl -XGET 'http://localhost:9200/_nodes/stats/indices/?fields=field1,field2&pretty' +# Node level +curl -XGET 'http://localhost:9200/_nodes/stats/indices/fielddata?fields=field1,field2&pretty' -# Indices Stat +# Index level curl -XGET 'http://localhost:9200/_stats/fielddata/?fields=field1,field2&pretty' # You can use wildcards for field names +curl -XGET 'http://localhost:9200/_nodes/stats/indices/fielddata?fields=field*&pretty' curl -XGET 'http://localhost:9200/_stats/fielddata/?fields=field*&pretty' -curl -XGET 'http://localhost:9200/_nodes/stats/indices/?fields=field*&pretty' -------------------------------------------------- +Supported metrics are: + +* `completion` +* `docs` +* `fielddata` +* `flush` +* `get` +* `indexing` +* `merge` +* `query_cache` +* `recovery` +* `refresh` +* `request_cache` +* `search` +* `segments` +* `store` +* `suggest` +* `translog` +* `warmer` + [float] [[search-groups]] === Search groups diff --git a/docs/reference/indices/flush.asciidoc b/docs/reference/indices/flush.asciidoc index 5864c16d4c1..2b9f519e17c 100644 --- a/docs/reference/indices/flush.asciidoc +++ b/docs/reference/indices/flush.asciidoc @@ -74,7 +74,7 @@ the <> API: [source,sh] -------------------------------------------------- -GET twitter/_stats/commit?level=shards +GET twitter/_stats?level=shards -------------------------------------------------- // CONSOLE // TEST[s/^/PUT twitter\n/] diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml index 0710b63e5bb..a48907b0205 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml @@ -100,3 +100,17 @@ setup: - is_false: indices.test1 - is_true: indices.test2 +--- +"Indices stats unrecognized parameter": + - skip: + version: " - 5.99.99" + reason: awaits strict stats handling to be backported to 5.x + - do: + indices.stats: + metric: [ fieldata ] + ignore: 400 + + - match: { status: 400 } + - match: { error.type: illegal_argument_exception } + - match: { error.reason: "request [/_stats/fieldata] contains unrecognized metric: [fieldata] -> did you mean [fielddata]?" } + diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml index 1cd9fef0258..1ec7ddabf98 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml @@ -20,3 +20,17 @@ level: "indices" - is_true: nodes.$master.indices.indices + +--- +"Nodes stats unrecognized parameter": + - skip: + version: " - 5.99.99" + reason: awaits strict stats handling to be backported to 5.x + - do: + nodes.stats: + metric: [ transprot ] + ignore: 400 + + - match: { status: 400 } + - match: { error.type: illegal_argument_exception } + - match: { error.reason: "request [/_nodes/stats/transprot] contains unrecognized metric: [transprot] -> did you mean [transport]?" } From f03723a812e184bb448350028a187f5b98eb865d Mon Sep 17 00:00:00 2001 From: Bryan Karlovitz Date: Tue, 15 Nov 2016 11:16:47 -0600 Subject: [PATCH 09/25] Minor style change to getting-started.asciidoc (#21571) * In line 525, change the phrase "... with as little network roundtrips as possible." to "... with as few network roundtrips as possible." --- docs/reference/getting-started.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/getting-started.asciidoc b/docs/reference/getting-started.asciidoc index 5e7830ce90c..b2cbf33804a 100755 --- a/docs/reference/getting-started.asciidoc +++ b/docs/reference/getting-started.asciidoc @@ -522,7 +522,7 @@ instead of deleting all documents with the Delete By Query API. === Batch Processing -In addition to being able to index, update, and delete individual documents, Elasticsearch also provides the ability to perform any of the above operations in batches using the <>. This functionality is important in that it provides a very efficient mechanism to do multiple operations as fast as possible with as little network roundtrips as possible. +In addition to being able to index, update, and delete individual documents, Elasticsearch also provides the ability to perform any of the above operations in batches using the <>. This functionality is important in that it provides a very efficient mechanism to do multiple operations as fast as possible with as few network roundtrips as possible. As a quick example, the following call indexes two documents (ID 1 - John Doe and ID 2 - Jane Doe) in one bulk operation: From cd4634bdc653fcb4e9bb10aeee9307ecdcee50db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Mon, 14 Nov 2016 18:34:18 +0100 Subject: [PATCH 10/25] Fix time zone rounding edge case for DST overlaps When using TimeUnitRounding with a DAY_OF_MONTH unit, failing tests in #20833 uncovered an issue when the DST shift happenes just one hour after midnight local time and sets back the clock to midnight, leading to an overlap. Previously this would lead to two different rounding values, depending on whether a date before or after the transition was rounded. This change detects this special case and correct for it by using the previous rounding date for both cases. Closes #20833 --- .../common/rounding/Rounding.java | 41 +++++++++++++++---- .../rounding/TimeZoneRoundingTests.java | 38 +++++++++++++++++ 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/common/rounding/Rounding.java b/core/src/main/java/org/elasticsearch/common/rounding/Rounding.java index ad9f926e881..50461d6184a 100644 --- a/core/src/main/java/org/elasticsearch/common/rounding/Rounding.java +++ b/core/src/main/java/org/elasticsearch/common/rounding/Rounding.java @@ -128,15 +128,38 @@ public abstract class Rounding implements Streamable { @Override public long round(long utcMillis) { long rounded = field.roundFloor(utcMillis); - if (timeZone.isFixed() == false && timeZone.getOffset(utcMillis) != timeZone.getOffset(rounded)) { - // in this case, we crossed a time zone transition. In some edge - // cases this will - // result in a value that is not a rounded value itself. We need - // to round again - // to make sure. This will have no affect in cases where - // 'rounded' was already a proper - // rounded value - rounded = field.roundFloor(rounded); + if (timeZone.isFixed() == false) { + // special cases for non-fixed time zones with dst transitions + if (timeZone.getOffset(utcMillis) != timeZone.getOffset(rounded)) { + /* + * the offset change indicates a dst transition. In some + * edge cases this will result in a value that is not a + * rounded value before the transition. We round again to + * make sure we really return a rounded value. This will + * have no effect in cases where we already had a valid + * rounded value + */ + rounded = field.roundFloor(rounded); + } else { + /* + * check if the current time instant is at a start of a DST + * overlap by comparing the offset of the instant and the + * previous millisecond. We want to detect negative offset + * changes that result in an overlap + */ + if (timeZone.getOffset(rounded) < timeZone.getOffset(rounded - 1)) { + /* + * we are rounding a date just after a DST overlap. if + * the overlap is smaller than the time unit we are + * rounding to, we want to add the overlapping part to + * the following rounding interval + */ + long previousRounded = field.roundFloor(rounded - 1); + if (rounded - previousRounded < field.getDurationField().getUnitMillis()) { + rounded = previousRounded; + } + } + } } assert rounded == field.roundFloor(rounded); return rounded; diff --git a/core/src/test/java/org/elasticsearch/common/rounding/TimeZoneRoundingTests.java b/core/src/test/java/org/elasticsearch/common/rounding/TimeZoneRoundingTests.java index 159b8693b84..2c1c480c6a5 100644 --- a/core/src/test/java/org/elasticsearch/common/rounding/TimeZoneRoundingTests.java +++ b/core/src/test/java/org/elasticsearch/common/rounding/TimeZoneRoundingTests.java @@ -514,6 +514,44 @@ public class TimeZoneRoundingTests extends ESTestCase { } } + /** + * tests for dst transition with overlaps and day roundings. + */ + public void testDST_END_Edgecases() { + // First case, dst happens at 1am local time, switching back one hour. + // We want the overlapping hour to count for the next day, making it a 25h interval + + DateTimeUnit timeUnit = DateTimeUnit.DAY_OF_MONTH; + DateTimeZone tz = DateTimeZone.forID("Atlantic/Azores"); + Rounding rounding = new Rounding.TimeUnitRounding(timeUnit, tz); + + // Sunday, 29 October 2000, 01:00:00 clocks were turned backward 1 hour + // to Sunday, 29 October 2000, 00:00:00 local standard time instead + + long midnightBeforeTransition = time("2000-10-29T00:00:00", tz); + long nextMidnight = time("2000-10-30T00:00:00", tz); + + assertInterval(midnightBeforeTransition, nextMidnight, rounding, 25 * 60, tz); + + // Second case, dst happens at 0am local time, switching back one hour to 23pm local time. + // We want the overlapping hour to count for the previous day here + + tz = DateTimeZone.forID("America/Lima"); + rounding = new Rounding.TimeUnitRounding(timeUnit, tz); + + // Sunday, 1 April 1990, 00:00:00 clocks were turned backward 1 hour to + // Saturday, 31 March 1990, 23:00:00 local standard time instead + + midnightBeforeTransition = time("1990-03-31T00:00:00.000-04:00"); + nextMidnight = time("1990-04-01T00:00:00.000-05:00"); + assertInterval(midnightBeforeTransition, nextMidnight, rounding, 25 * 60, tz); + + // make sure the next interval is 24h long again + long midnightAfterTransition = time("1990-04-01T00:00:00.000-05:00"); + nextMidnight = time("1990-04-02T00:00:00.000-05:00"); + assertInterval(midnightAfterTransition, nextMidnight, rounding, 24 * 60, tz); + } + /** * Test that time zones are correctly parsed. There is a bug with * Joda 2.9.4 (see https://github.com/JodaOrg/joda-time/issues/373) From 96122aa5188c89afcbe27be5f22ca85677527382 Mon Sep 17 00:00:00 2001 From: Lee Hinman Date: Tue, 15 Nov 2016 10:36:57 -0700 Subject: [PATCH 11/25] Be strict when parsing values searching for booleans (#21555) This changes only the query parsing behavior to be strict when searching on boolean values. We continue to accept the variety of values during index time, but searches will only be parsed using `"true"` or `"false"`. Resolves #21545 --- .../index/mapper/BooleanFieldMapper.java | 17 ++++++++--------- .../ExternalValuesMapperIntegrationIT.java | 2 +- .../search/query/QueryStringIT.java | 8 ++++++++ docs/reference/mapping/types/boolean.asciidoc | 8 ++++---- .../migration/migrate_6_0/search.asciidoc | 4 ++++ 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java index 3a4ce5bd123..8e087f72f0a 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java @@ -152,16 +152,15 @@ public class BooleanFieldMapper extends FieldMapper { } else { sValue = value.toString(); } - if (sValue.length() == 0) { - return Values.FALSE; + switch (sValue) { + case "true": + return Values.TRUE; + case "false": + return Values.FALSE; + default: + throw new IllegalArgumentException("Can't parse boolean value [" + + sValue + "], expected [true] or [false]"); } - if (sValue.length() == 1 && sValue.charAt(0) == 'F') { - return Values.FALSE; - } - if (Booleans.parseBoolean(sValue, false)) { - return Values.TRUE; - } - return Values.FALSE; } @Override diff --git a/core/src/test/java/org/elasticsearch/index/mapper/ExternalValuesMapperIntegrationIT.java b/core/src/test/java/org/elasticsearch/index/mapper/ExternalValuesMapperIntegrationIT.java index c75871e43b3..bc2d6c564ec 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/ExternalValuesMapperIntegrationIT.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/ExternalValuesMapperIntegrationIT.java @@ -106,7 +106,7 @@ public class ExternalValuesMapperIntegrationIT extends ESIntegTestCase { SearchResponse response; response = client().prepareSearch("test-idx") - .setPostFilter(QueryBuilders.termQuery("field.bool", "T")) + .setPostFilter(QueryBuilders.termQuery("field.bool", "true")) .execute().actionGet(); assertThat(response.getHits().totalHits(), equalTo((long) 1)); diff --git a/core/src/test/java/org/elasticsearch/search/query/QueryStringIT.java b/core/src/test/java/org/elasticsearch/search/query/QueryStringIT.java index 79dea0e74b5..540c67ae39d 100644 --- a/core/src/test/java/org/elasticsearch/search/query/QueryStringIT.java +++ b/core/src/test/java/org/elasticsearch/search/query/QueryStringIT.java @@ -247,6 +247,14 @@ public class QueryStringIT extends ESIntegTestCase { assertHitCount(resp, 1L); } + public void testBooleanStrictQuery() throws Exception { + Exception e = expectThrows(Exception.class, () -> + client().prepareSearch("test").setQuery( + queryStringQuery("foo").field("f_bool")).get()); + assertThat(ExceptionsHelper.detailedMessage(e), + containsString("Can't parse boolean value [foo], expected [true] or [false]")); + } + private void assertHits(SearchHits hits, String... ids) { assertThat(hits.totalHits(), equalTo((long) ids.length)); Set hitIds = new HashSet<>(); diff --git a/docs/reference/mapping/types/boolean.asciidoc b/docs/reference/mapping/types/boolean.asciidoc index a5f559facc2..08b9cc8bdab 100644 --- a/docs/reference/mapping/types/boolean.asciidoc +++ b/docs/reference/mapping/types/boolean.asciidoc @@ -32,21 +32,21 @@ PUT my_index POST my_index/my_type/1 { - "is_published": true <1> + "is_published": 1 <1> } GET my_index/_search { "query": { "term": { - "is_published": 1 <2> + "is_published": true <2> } } } -------------------------------------------------- // CONSOLE -<1> Indexing a document with a JSON `true`. -<2> Querying for the document with `1`, which is interpreted as `true`. +<1> Indexing a document with `1`, which is interpreted as `true`. +<1> Searching for documents with a JSON `true`. Aggregations like the <> use `1` and `0` for the `key`, and the strings `"true"` and diff --git a/docs/reference/migration/migrate_6_0/search.asciidoc b/docs/reference/migration/migrate_6_0/search.asciidoc index 5a98edd6d1a..fe72768e590 100644 --- a/docs/reference/migration/migrate_6_0/search.asciidoc +++ b/docs/reference/migration/migrate_6_0/search.asciidoc @@ -5,3 +5,7 @@ * The `collect_payloads` parameter of the `span_near` query has been removed. Payloads will be loaded when needed. + +* Queries on boolean fields now strictly parse boolean-like values. This means + only the strings `"true"` and `"false"` will be parsed into their boolean + counterparts. Other strings will cause an error to be thrown. From cfabc95f59e979861d574eb064de7cc972adbd20 Mon Sep 17 00:00:00 2001 From: Clinton Gormley Date: Tue, 15 Nov 2016 17:37:35 +0000 Subject: [PATCH 12/25] Fixed bad asciidoc ID in node stats --- docs/reference/cluster/nodes-stats.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/cluster/nodes-stats.asciidoc b/docs/reference/cluster/nodes-stats.asciidoc index 493d5db5613..3cae4302922 100644 --- a/docs/reference/cluster/nodes-stats.asciidoc +++ b/docs/reference/cluster/nodes-stats.asciidoc @@ -280,7 +280,7 @@ the current running process: Size in bytes of virtual memory that is guaranteed to be available to the running process [float] -[[indices-stats]] +[[node-indices-stats]] === Indices statistics You can get information about indices stats on node level or on index level. From a4e88bb64a92de5b480edc612da25bd2e06a193f Mon Sep 17 00:00:00 2001 From: Clinton Gormley Date: Tue, 15 Nov 2016 17:50:23 +0000 Subject: [PATCH 13/25] Fixed bad asciidoc in boolean mapping docs --- docs/reference/mapping/types/boolean.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/mapping/types/boolean.asciidoc b/docs/reference/mapping/types/boolean.asciidoc index 08b9cc8bdab..d273dddb27d 100644 --- a/docs/reference/mapping/types/boolean.asciidoc +++ b/docs/reference/mapping/types/boolean.asciidoc @@ -46,7 +46,7 @@ GET my_index/_search -------------------------------------------------- // CONSOLE <1> Indexing a document with `1`, which is interpreted as `true`. -<1> Searching for documents with a JSON `true`. +<2> Searching for documents with a JSON `true`. Aggregations like the <> use `1` and `0` for the `key`, and the strings `"true"` and From d99d02ecc39cf9258c500b612f268436582c681d Mon Sep 17 00:00:00 2001 From: Boaz Leskes Date: Tue, 15 Nov 2016 17:57:24 +0000 Subject: [PATCH 14/25] InternalTestCluster: when restarting a node we should validate the cluster is formed via the node we just restarted This is to deal with potential delays in processing the fact that node was node is restarted. --- .../elasticsearch/test/InternalTestCluster.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) 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 3c29b878e7a..154cd101463 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java +++ b/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java @@ -1070,10 +1070,15 @@ public final class InternalTestCluster extends TestCluster { /** ensure a cluster is form with {@link #nodes}.size() nodes. */ private void validateClusterFormed() { - final int size = nodes.size(); String name = randomFrom(random, getNodeNames()); - logger.trace("validating cluster formed via [{}], expecting [{}]", name, size); - final Client client = client(name); + validateClusterFormed(name); + } + + /** ensure a cluster is form with {@link #nodes}.size() nodes, but do so by using the client of the specified node */ + private void validateClusterFormed(String viaNode) { + final int size = nodes.size(); + logger.trace("validating cluster formed via [{}], expecting [{}]", viaNode, size); + final Client client = client(viaNode); ClusterHealthResponse response = client.admin().cluster().prepareHealth().setWaitForNodes(Integer.toString(size)).get(); if (response.isTimedOut()) { logger.warn("failed to wait for a cluster of size [{}], got [{}]", size, response); @@ -1485,7 +1490,9 @@ public final class InternalTestCluster extends TestCluster { if (callback.validateClusterForming() || updateMinMaster) { // we have to validate cluster size if updateMinMaster == true, because we need the // second node to join in order to increment min_master_nodes back to 2. - validateClusterFormed(); + // we also have to do via the node that was just restarted as it may be that the master didn't yet process + // the fact it left + validateClusterFormed(nodeAndClient.name); } if (updateMinMaster) { updateMinMasterNodes(masterNodesCount); From 17a2fffc9be50102fa5a9da72053c82df23b1a64 Mon Sep 17 00:00:00 2001 From: Lee Hinman Date: Tue, 15 Nov 2016 11:02:43 -0700 Subject: [PATCH 15/25] [DOCS] Mention "all-fields" mode doesn't search across nested documents --- docs/reference/query-dsl/query-string-query.asciidoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/reference/query-dsl/query-string-query.asciidoc b/docs/reference/query-dsl/query-string-query.asciidoc index 70f976d1d56..28d7be357c9 100644 --- a/docs/reference/query-dsl/query-string-query.asciidoc +++ b/docs/reference/query-dsl/query-string-query.asciidoc @@ -109,7 +109,8 @@ which field to search on. It defaults to `_all` field. If the `_all` field is disabled, the `query_string` query will automatically attempt to determine the existing fields in the index's mapping that are -queryable, and perform the search on those fields. +queryable, and perform the search on those fields. Note that this will not +include nested documents, use a nested query to search those documents. [float] ==== Multi Field From 40e0162e616445206a26197ef18f6370acbb30eb Mon Sep 17 00:00:00 2001 From: Yannick Welsch Date: Tue, 15 Nov 2016 21:38:58 +0100 Subject: [PATCH 16/25] Remove cluster update task when task times out (#21578) Fixes an issue where the cluster service does not remove an update task from its internal data structures that are used for batching cluster state updates. * review comments * checkstyle --- .../cluster/service/ClusterService.java | 33 +++++++++++--- .../cluster/service/ClusterServiceTests.java | 45 +++++++++++++++++++ 2 files changed, 71 insertions(+), 7 deletions(-) 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 ce5c0f3e258..6d69d57ad1f 100644 --- a/core/src/main/java/org/elasticsearch/cluster/service/ClusterService.java +++ b/core/src/main/java/org/elasticsearch/cluster/service/ClusterService.java @@ -70,6 +70,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -114,7 +115,7 @@ public class ClusterService extends AbstractLifecycleComponent { private final Collection priorityClusterStateListeners = new CopyOnWriteArrayList<>(); private final Collection clusterStateListeners = new CopyOnWriteArrayList<>(); private final Collection lastClusterStateListeners = new CopyOnWriteArrayList<>(); - private final Map> updateTasksPerExecutor = new HashMap<>(); + final Map> updateTasksPerExecutor = new HashMap<>(); // TODO this is rather frequently changing I guess a Synced Set would be better here and a dedicated remove API private final Collection postAppliedListeners = new CopyOnWriteArrayList<>(); private final Iterable preAppliedListeners = Iterables.concat(priorityClusterStateListeners, @@ -454,7 +455,8 @@ public class ClusterService extends AbstractLifecycleComponent { ).collect(Collectors.toList()); synchronized (updateTasksPerExecutor) { - List existingTasks = updateTasksPerExecutor.computeIfAbsent(executor, k -> new ArrayList<>()); + LinkedHashSet existingTasks = updateTasksPerExecutor.computeIfAbsent(executor, + k -> new LinkedHashSet<>(updateTasks.size())); for (@SuppressWarnings("unchecked") UpdateTask existing : existingTasks) { if (tasksIdentity.containsKey(existing.task)) { throw new IllegalStateException("task [" + executor.describeTasks(Collections.singletonList(existing.task)) + @@ -466,12 +468,29 @@ public class ClusterService extends AbstractLifecycleComponent { final UpdateTask firstTask = updateTasks.get(0); - if (config.timeout() != null) { - updateTasksExecutor.execute(firstTask, threadPool.scheduler(), config.timeout(), () -> threadPool.generic().execute(() -> { + final TimeValue timeout = config.timeout(); + if (timeout != null) { + updateTasksExecutor.execute(firstTask, threadPool.scheduler(), timeout, () -> threadPool.generic().execute(() -> { + final ArrayList> toRemove = new ArrayList<>(); for (UpdateTask task : updateTasks) { if (task.processed.getAndSet(true) == false) { - logger.debug("cluster state update task [{}] timed out after [{}]", source, config.timeout()); - task.listener.onFailure(source, new ProcessClusterEventTimeoutException(config.timeout(), source)); + logger.debug("cluster state update task [{}] timed out after [{}]", source, timeout); + toRemove.add(task); + } + } + if (toRemove.isEmpty() == false) { + ClusterStateTaskExecutor clusterStateTaskExecutor = toRemove.get(0).executor; + synchronized (updateTasksPerExecutor) { + LinkedHashSet existingTasks = updateTasksPerExecutor.get(clusterStateTaskExecutor); + if (existingTasks != null) { + existingTasks.removeAll(toRemove); + if (existingTasks.isEmpty()) { + updateTasksPerExecutor.remove(clusterStateTaskExecutor); + } + } + } + for (UpdateTask task : toRemove) { + task.listener.onFailure(source, new ProcessClusterEventTimeoutException(timeout, source)); } } })); @@ -567,7 +586,7 @@ public class ClusterService extends AbstractLifecycleComponent { final ArrayList> toExecute = new ArrayList<>(); final Map> processTasksBySource = new HashMap<>(); synchronized (updateTasksPerExecutor) { - List pending = updateTasksPerExecutor.remove(executor); + LinkedHashSet pending = updateTasksPerExecutor.remove(executor); if (pending != null) { for (UpdateTask task : pending) { if (task.processed.getAndSet(true) == false) { diff --git a/core/src/test/java/org/elasticsearch/cluster/service/ClusterServiceTests.java b/core/src/test/java/org/elasticsearch/cluster/service/ClusterServiceTests.java index bede01ed21b..026d3a16185 100644 --- a/core/src/test/java/org/elasticsearch/cluster/service/ClusterServiceTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/service/ClusterServiceTests.java @@ -148,6 +148,51 @@ public class ClusterServiceTests extends ESTestCase { return timedClusterService; } + public void testTimedOutUpdateTaskCleanedUp() throws Exception { + final CountDownLatch block = new CountDownLatch(1); + clusterService.submitStateUpdateTask("block-task", new ClusterStateUpdateTask() { + @Override + public ClusterState execute(ClusterState currentState) { + try { + block.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return currentState; + } + + @Override + public void onFailure(String source, Exception e) { + throw new RuntimeException(e); + } + }); + + final CountDownLatch block2 = new CountDownLatch(1); + clusterService.submitStateUpdateTask("test", new ClusterStateUpdateTask() { + @Override + public ClusterState execute(ClusterState currentState) { + block2.countDown(); + return currentState; + } + + @Override + public TimeValue timeout() { + return TimeValue.ZERO; + } + + @Override + public void onFailure(String source, Exception e) { + block2.countDown(); + } + }); + block.countDown(); + block2.await(); + synchronized (clusterService.updateTasksPerExecutor) { + assertTrue("expected empty map but was " + clusterService.updateTasksPerExecutor, + clusterService.updateTasksPerExecutor.isEmpty()); + } + } + public void testTimeoutUpdateTask() throws Exception { final CountDownLatch block = new CountDownLatch(1); clusterService.submitStateUpdateTask("test1", new ClusterStateUpdateTask() { From 17b0041aaf036bde587981475823dff6976e12ba Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Tue, 15 Nov 2016 16:26:37 -0500 Subject: [PATCH 17/25] Strict level parsing for indices stats A previous commit added strict level parsing for the node stats API, but that commit missed adding the same for the indices stats API. This commit rectifies this miss. Relates #21577 --- .../indices/stats/IndicesStatsResponse.java | 8 ++-- .../stats/IndicesStatsResponseTests.java | 43 +++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 core/src/test/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponseTests.java diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponse.java b/core/src/main/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponse.java index 3cbd7db66aa..839c27e0b8a 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponse.java +++ b/core/src/main/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponse.java @@ -152,12 +152,14 @@ public class IndicesStatsResponse extends BroadcastResponse implements ToXConten @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - String level = params.param("level", "indices"); - boolean isLevelValid = "indices".equalsIgnoreCase(level) || "shards".equalsIgnoreCase(level) || "cluster".equalsIgnoreCase(level); + final String level = params.param("level", "indices"); + final boolean isLevelValid = + "cluster".equalsIgnoreCase(level) || "indices".equalsIgnoreCase(level) || "shards".equalsIgnoreCase(level); if (!isLevelValid) { - return builder; + throw new IllegalArgumentException("level parameter must be one of [cluster] or [indices] or [shards] but was [" + level + "]"); } + builder.startObject("_all"); builder.startObject("primaries"); diff --git a/core/src/test/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponseTests.java b/core/src/test/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponseTests.java new file mode 100644 index 00000000000..b419be0465b --- /dev/null +++ b/core/src/test/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponseTests.java @@ -0,0 +1,43 @@ +/* + * 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.action.admin.indices.stats; + +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.test.ESTestCase; + +import java.util.Collections; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.object.HasToString.hasToString; + + +public class IndicesStatsResponseTests extends ESTestCase { + + public void testInvalidLevel() { + final IndicesStatsResponse response = new IndicesStatsResponse(); + final String level = randomAsciiOfLength(16); + final ToXContent.Params params = new ToXContent.MapParams(Collections.singletonMap("level", level)); + final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> response.toXContent(null, params)); + assertThat( + e, + hasToString(containsString("level parameter must be one of [cluster] or [indices] or [shards] but was [" + level + "]"))); + } + +} From 6a8a3e77ed3a534499476f3957db1c63147cbea2 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Tue, 15 Nov 2016 17:43:19 -0500 Subject: [PATCH 18/25] Reduce skip version for stats API parameter tests This commit reduces the skip version for the stats API unrecognized parameter tests now that the logic for unrecognized parameters has been backported to 5.x. --- .../resources/rest-api-spec/test/indices.stats/10_index.yaml | 2 +- .../main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml index a48907b0205..2a06e70d101 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml @@ -103,7 +103,7 @@ setup: --- "Indices stats unrecognized parameter": - skip: - version: " - 5.99.99" + version: " - 5.0.99" reason: awaits strict stats handling to be backported to 5.x - do: indices.stats: diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml index 1ec7ddabf98..277a54234df 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml @@ -24,7 +24,7 @@ --- "Nodes stats unrecognized parameter": - skip: - version: " - 5.99.99" + version: " - 5.0.99" reason: awaits strict stats handling to be backported to 5.x - do: nodes.stats: From cca22088aca259bb750f41e9888f5195a8a32a2e Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Tue, 15 Nov 2016 17:51:28 -0500 Subject: [PATCH 19/25] Fix skip reason for stats API parameters test This commit corrects the reasons that the stats API parameters tests are skipped against 5.0 nodes. --- .../resources/rest-api-spec/test/indices.stats/10_index.yaml | 2 +- .../main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml index 2a06e70d101..933fe443b71 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml @@ -104,7 +104,7 @@ setup: "Indices stats unrecognized parameter": - skip: version: " - 5.0.99" - reason: awaits strict stats handling to be backported to 5.x + reason: strict stats handling does not exist in 5.0 - do: indices.stats: metric: [ fieldata ] diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml index 277a54234df..039a24284ea 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/10_basic.yaml @@ -25,7 +25,7 @@ "Nodes stats unrecognized parameter": - skip: version: " - 5.0.99" - reason: awaits strict stats handling to be backported to 5.x + reason: strict stats handling does not exist in 5.0 - do: nodes.stats: metric: [ transprot ] From e66261eee96ad92e4e6c822a5d34af5cd05efff1 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Tue, 15 Nov 2016 16:21:41 -0500 Subject: [PATCH 20/25] Handle release of 5.0.1 Adds a version constant for it, bwc indices, and a vagrant upgrade-from version. Also bumps the "upgrade from" version for the backwards-5.0 test and adds `skip`s for tests that don't fail against 5.0 so we skip them during the backwards testing. Finally, this skips the "Shrink index via API" test because it fails consistently for me. Inconsistently for CI, but consistently for me. I'll work on making it consistent tomorrow. --- .../main/java/org/elasticsearch/Version.java | 5 ++++- .../java/org/elasticsearch/VersionTests.java | 12 ++++++------ .../test/resources/indices/bwc/index-5.0.1.zip | Bin 0 -> 238020 bytes .../test/resources/indices/bwc/repo-5.0.1.zip | Bin 0 -> 115121 bytes distribution/licenses/joda-time-2.9.5.jar.sha1 | 1 + qa/vagrant/versions | 1 + .../test/indices.shrink/10_basic.yaml | 5 ++++- .../test/indices.stats/10_index.yaml | 1 - 8 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 core/src/test/resources/indices/bwc/index-5.0.1.zip create mode 100644 core/src/test/resources/indices/bwc/repo-5.0.1.zip create mode 100644 distribution/licenses/joda-time-2.9.5.jar.sha1 diff --git a/core/src/main/java/org/elasticsearch/Version.java b/core/src/main/java/org/elasticsearch/Version.java index 2d61fb8194a..ac5cf9de868 100644 --- a/core/src/main/java/org/elasticsearch/Version.java +++ b/core/src/main/java/org/elasticsearch/Version.java @@ -19,7 +19,6 @@ package org.elasticsearch; -import org.apache.lucene.util.MathUtil; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.Strings; import org.elasticsearch.common.SuppressForbidden; @@ -92,6 +91,8 @@ public class Version { public static final Version V_5_0_0_rc1 = new Version(V_5_0_0_rc1_ID, org.apache.lucene.util.Version.LUCENE_6_2_0); public static final int V_5_0_0_ID = 5000099; public static final Version V_5_0_0 = new Version(V_5_0_0_ID, org.apache.lucene.util.Version.LUCENE_6_2_0); + public static final int V_5_0_1_ID = 5000199; + public static final Version V_5_0_1 = new Version(V_5_0_1_ID, org.apache.lucene.util.Version.LUCENE_6_2_1); public static final int V_6_0_0_alpha1_ID = 6000001; public static final Version V_6_0_0_alpha1 = new Version(V_6_0_0_alpha1_ID, org.apache.lucene.util.Version.LUCENE_6_3_0); public static final Version CURRENT = V_6_0_0_alpha1; @@ -118,6 +119,8 @@ public class Version { switch (id) { case V_6_0_0_alpha1_ID: return V_6_0_0_alpha1; + case V_5_0_1_ID: + return V_5_0_1; case V_5_0_0_ID: return V_5_0_0; case V_5_0_0_rc1_ID: diff --git a/core/src/test/java/org/elasticsearch/VersionTests.java b/core/src/test/java/org/elasticsearch/VersionTests.java index f8c31ee3189..9499b79432c 100644 --- a/core/src/test/java/org/elasticsearch/VersionTests.java +++ b/core/src/test/java/org/elasticsearch/VersionTests.java @@ -19,15 +19,12 @@ package org.elasticsearch; -import org.elasticsearch.action.ShardValidateQueryRequestTests; -import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.query.QueryStringQueryBuilder; -import org.elasticsearch.monitor.os.OsStats; import org.elasticsearch.index.query.SimpleQueryStringBuilder; +import org.elasticsearch.monitor.os.OsStats; import org.elasticsearch.script.Script; import org.elasticsearch.search.internal.AliasFilter; import org.elasticsearch.test.ESTestCase; @@ -136,8 +133,11 @@ public class VersionTests extends ESTestCase { assertThat(Version.V_5_0_0_alpha1.minimumCompatibilityVersion(), equalTo(Version.V_5_0_0_alpha1)); // from 6.0 on we are supporting the latest minor of the previous major... this might fail once we add a new version ie. 5.x is // released since we need to bump the supported minor in Version#minimumCompatibilityVersion() - assertThat("did you miss to bump the minor in Version#minimumCompatibilityVersion()", - Version.V_6_0_0_alpha1.minimumCompatibilityVersion(), equalTo(VersionUtils.getPreviousVersion(Version.V_6_0_0_alpha1))); + Version lastVersion = VersionUtils.getPreviousVersion(Version.V_6_0_0_alpha1); + assertEquals(lastVersion.major, Version.V_6_0_0_alpha1.minimumCompatibilityVersion().major); + assertEquals("did you miss to bump the minor in Version#minimumCompatibilityVersion()", + lastVersion.minor, Version.V_6_0_0_alpha1.minimumCompatibilityVersion().minor); + assertEquals(0, Version.V_6_0_0_alpha1.minimumCompatibilityVersion().revision); } public void testToString() { diff --git a/core/src/test/resources/indices/bwc/index-5.0.1.zip b/core/src/test/resources/indices/bwc/index-5.0.1.zip new file mode 100644 index 0000000000000000000000000000000000000000..8b58866a970673fedc0e7caef95b3aa8e980d65f GIT binary patch literal 238020 zcmbq)Wl$yEmL(MK4u!kBQ@Fc3g}b|ZQMkLi7Vd5rcPXH73c0vDT#5_K_w}2O>3K1) zdwM1#c1HflTzl`c*V>tJ@*GtKC}>28zYmH)XSsj7_@5^j2qFjzQx8*CElmUns9iTk zT_SfzT~8k*2uSEhNC*gM?7wbQ{g;m;{rlri&K8#L|Cb;P{}cnt{|>_T518x!Di-m7 zg2Dc07-M%2QxD63pb`F+)xXH>?+oD~{zeme=eh9uE9v>ajPzfiSvxqJnL03YvABEu z+mQVY{I~tnkQpY;$`6ZThf^-bv+i!E<6`FE;&tEt(87*Yt#KNr>T-ljRm{uAj_tJ9 z7zKp;59VWgEYO~Om6Sp^9)xo#=9JAJ^V%O^i*!eO4)Vs`?wiEkj|#1@H4haK;Y`LH z7j`M@iK4_<4dGDyzN#@E`x(wo3d75L%8Onnd)hhU;f

Q-3BS_ULQX>^FBJ&FoIn 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

l>sF}OHu%C?px&gWLF^D8wDf?q^- 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⋙NdM^()* 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 literal 0 HcmV?d00001 diff --git a/distribution/licenses/joda-time-2.9.5.jar.sha1 b/distribution/licenses/joda-time-2.9.5.jar.sha1 new file mode 100644 index 00000000000..ecf1c781556 --- /dev/null +++ b/distribution/licenses/joda-time-2.9.5.jar.sha1 @@ -0,0 +1 @@ +5f01da7306363fad2028b916f3eab926262de928 \ No newline at end of file diff --git a/qa/vagrant/versions b/qa/vagrant/versions index 0062ac97180..2ea69c82e4b 100644 --- a/qa/vagrant/versions +++ b/qa/vagrant/versions @@ -1 +1,2 @@ 5.0.0 +5.0.1 diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.shrink/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.shrink/10_basic.yaml index b391032bee3..7e491f5715a 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.shrink/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.shrink/10_basic.yaml @@ -1,5 +1,8 @@ --- "Shrink index via API": + - skip: + features: always + reason: Fails consistently for Nik and sometimes for Jenkins. Skip until we can get it passing consistently. # creates an index with one document solely allocated on the master node # and shrinks it into a new index with a single shard # we don't do the relocation to a single node after the index is created @@ -9,7 +12,7 @@ - do: cluster.state: {} # Get master node id - + - set: { master_node: master } - do: diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml index 933fe443b71..d3f4134c0f6 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.stats/10_index.yaml @@ -113,4 +113,3 @@ setup: - match: { status: 400 } - match: { error.type: illegal_argument_exception } - match: { error.reason: "request [/_stats/fieldata] contains unrecognized metric: [fieldata] -> did you mean [fielddata]?" } - From 4ccd8e79c12ee45d5260d7a054d44bc56b6242e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Tue, 15 Nov 2016 19:06:35 +0100 Subject: [PATCH 21/25] Docs: Clarify date_histogram bucket sizes for DST time zones Added a warning note that clarifies bucket sizes diverging from the intended `interval` size when using a time zone that has DST changes. Closes #18805 --- .../bucket/datehistogram-aggregation.asciidoc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/reference/aggregations/bucket/datehistogram-aggregation.asciidoc b/docs/reference/aggregations/bucket/datehistogram-aggregation.asciidoc index 4d9147067ec..adf6e572d4c 100644 --- a/docs/reference/aggregations/bucket/datehistogram-aggregation.asciidoc +++ b/docs/reference/aggregations/bucket/datehistogram-aggregation.asciidoc @@ -196,6 +196,17 @@ second document falls into the bucket for 1 October 2015: <1> The `key_as_string` value represents midnight on each day in the specified time zone. +WARNING: When using time zones that follow DST (daylight savings time) changes, +buckets close to the moment when those changes happen can have slightly different +sizes than would be expected from the used `interval`. +For example, consider a DST start in the `CET` time zone: on 27 March 2016 at 2am, +clocks were turned forward 1 hour to 3am local time. When using `day` as `interval`, +the bucket covering that day will only hold data for 23 hours instead of the usual +24 hours for other buckets. The same is true for shorter intervals like e.g. 12h. +Here, we will have only a 11h bucket on the morning of 27 March when the DST shift +happens. + + ==== Offset The `offset` parameter is used to change the start value of each bucket by the From 2842e2752aaa05c8c0394b75b7e6149ff91ab596 Mon Sep 17 00:00:00 2001 From: David Pilato Date: Wed, 16 Nov 2016 09:52:08 +0100 Subject: [PATCH 22/25] Updated dynamic mapper section Backport of #21574 in master (6.0) --- docs/reference/docs/index_.asciidoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/reference/docs/index_.asciidoc b/docs/reference/docs/index_.asciidoc index b2d4bb562ea..8fb6fa983c9 100644 --- a/docs/reference/docs/index_.asciidoc +++ b/docs/reference/docs/index_.asciidoc @@ -69,8 +69,7 @@ section for more information on mapping definitions. Automatic index creation can be disabled by setting `action.auto_create_index` to `false` in the config file of all nodes. Automatic mapping creation can be disabled by setting -`index.mapper.dynamic` to `false` in the config files of all nodes (or -on the specific index settings). +`index.mapper.dynamic` to `false` per-index as an index setting. Automatic index creation can include a pattern based white/black list, for example, set `action.auto_create_index` to `+aaa*,-bbb*,+ccc*,-*` (+ From 00de8e07fc3df9c763bbc0b6890217dc5b6bee3e Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Wed, 16 Nov 2016 10:02:24 +0100 Subject: [PATCH 23/25] Do not cache term queries. (#21566) There have been reports that the query cache did not manage to speed up search requests when the query includes a large number of different sub queries since a single request may manage to exhaust the whole history (256 queries) while the query cache only starts caching queries once they appear multiple times in the history (#16031). On the other hand, increasing the size of the query cache is a bit controversial (#20116) so this pull request proposes a different approach that consists of never caching term queries, and not adding them to the history of queries either. The reasoning is that these queries should be fast anyway, regardless of caching, so taking them out of the equation should not cause any slow down. On the other hand, the fact that they are not added to the cache history anymore means that other queries have greater chances of being cached. --- .../common/settings/IndexScopedSettings.java | 1 + .../org/elasticsearch/index/IndexModule.java | 5 ++ .../ElasticsearchQueryCachingPolicy.java | 56 +++++++++++++++++ .../elasticsearch/index/shard/IndexShard.java | 6 +- .../ElasticsearchQueryCachingPolicyTests.java | 61 +++++++++++++++++++ .../elasticsearch/test/ESIntegTestCase.java | 3 + 6 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/org/elasticsearch/index/shard/ElasticsearchQueryCachingPolicy.java create mode 100644 core/src/test/java/org/elasticsearch/index/shard/ElasticsearchQueryCachingPolicyTests.java 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 1cc4f747a94..25a2fac7418 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java +++ b/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java @@ -137,6 +137,7 @@ public final class IndexScopedSettings extends AbstractScopedSettings { IndexModule.INDEX_STORE_PRE_LOAD_SETTING, IndexModule.INDEX_QUERY_CACHE_ENABLED_SETTING, IndexModule.INDEX_QUERY_CACHE_EVERYTHING_SETTING, + IndexModule.INDEX_QUERY_CACHE_TERM_QUERIES_SETTING, PrimaryShardAllocator.INDEX_RECOVERY_INITIAL_SHARDS_SETTING, FsDirectoryService.INDEX_LOCK_FACTOR_SETTING, EngineConfig.INDEX_CODEC_SETTING, diff --git a/core/src/main/java/org/elasticsearch/index/IndexModule.java b/core/src/main/java/org/elasticsearch/index/IndexModule.java index e3964653971..fe3ad975cfb 100644 --- a/core/src/main/java/org/elasticsearch/index/IndexModule.java +++ b/core/src/main/java/org/elasticsearch/index/IndexModule.java @@ -101,6 +101,11 @@ public final class IndexModule { public static final Setting INDEX_QUERY_CACHE_EVERYTHING_SETTING = Setting.boolSetting("index.queries.cache.everything", false, Property.IndexScope); + // This setting is an escape hatch in case not caching term queries would slow some users down + // Do not document. + public static final Setting INDEX_QUERY_CACHE_TERM_QUERIES_SETTING = + Setting.boolSetting("index.queries.cache.term_queries", false, Property.IndexScope); + private final IndexSettings indexSettings; private final IndexStoreConfig indexStoreConfig; private final AnalysisRegistry analysisRegistry; diff --git a/core/src/main/java/org/elasticsearch/index/shard/ElasticsearchQueryCachingPolicy.java b/core/src/main/java/org/elasticsearch/index/shard/ElasticsearchQueryCachingPolicy.java new file mode 100644 index 00000000000..3ea3955a1f4 --- /dev/null +++ b/core/src/main/java/org/elasticsearch/index/shard/ElasticsearchQueryCachingPolicy.java @@ -0,0 +1,56 @@ +/* + * 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.index.shard; + +import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryCachingPolicy; +import org.apache.lucene.search.TermQuery; + +import java.io.IOException; + +/** + * A {@link QueryCachingPolicy} that does not cache {@link TermQuery}s. + */ +final class ElasticsearchQueryCachingPolicy implements QueryCachingPolicy { + + private final QueryCachingPolicy in; + + ElasticsearchQueryCachingPolicy(QueryCachingPolicy in) { + this.in = in; + } + + @Override + public void onUse(Query query) { + if (query.getClass() != TermQuery.class) { + // Do not waste space in the history for term queries. The assumption + // is that these queries are very fast so not worth caching + in.onUse(query); + } + } + + @Override + public boolean shouldCache(Query query) throws IOException { + if (query.getClass() == TermQuery.class) { + return false; + } + return in.shouldCache(query); + } + +} 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 0de912ee2b0..ca197cfb68a 100644 --- a/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java +++ b/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java @@ -270,7 +270,11 @@ public class IndexShard extends AbstractIndexShardComponent implements IndicesCl if (IndexModule.INDEX_QUERY_CACHE_EVERYTHING_SETTING.get(settings)) { cachingPolicy = QueryCachingPolicy.ALWAYS_CACHE; } else { - cachingPolicy = new UsageTrackingQueryCachingPolicy(); + QueryCachingPolicy cachingPolicy = new UsageTrackingQueryCachingPolicy(); + if (IndexModule.INDEX_QUERY_CACHE_TERM_QUERIES_SETTING.get(settings) == false) { + cachingPolicy = new ElasticsearchQueryCachingPolicy(cachingPolicy); + } + this.cachingPolicy = cachingPolicy; } indexShardOperationsLock = new IndexShardOperationsLock(shardId, logger, threadPool); searcherWrapper = indexSearcherWrapper; diff --git a/core/src/test/java/org/elasticsearch/index/shard/ElasticsearchQueryCachingPolicyTests.java b/core/src/test/java/org/elasticsearch/index/shard/ElasticsearchQueryCachingPolicyTests.java new file mode 100644 index 00000000000..0344a15810f --- /dev/null +++ b/core/src/test/java/org/elasticsearch/index/shard/ElasticsearchQueryCachingPolicyTests.java @@ -0,0 +1,61 @@ +/* + * 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.index.shard; + +import org.apache.lucene.index.Term; +import org.apache.lucene.search.PhraseQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryCachingPolicy; +import org.apache.lucene.search.TermQuery; +import org.elasticsearch.test.ESTestCase; + +import java.io.IOException; + +public class ElasticsearchQueryCachingPolicyTests extends ESTestCase { + + public void testDoesNotCacheTermQueries() throws IOException { + QueryCachingPolicy policy = QueryCachingPolicy.ALWAYS_CACHE; + assertTrue(policy.shouldCache(new TermQuery(new Term("foo", "bar")))); + assertTrue(policy.shouldCache(new PhraseQuery("foo", "bar", "baz"))); + policy = new ElasticsearchQueryCachingPolicy(policy); + assertFalse(policy.shouldCache(new TermQuery(new Term("foo", "bar")))); + assertTrue(policy.shouldCache(new PhraseQuery("foo", "bar", "baz"))); + } + + public void testDoesNotPutTermQueriesIntoTheHistory() { + boolean[] used = new boolean[1]; + QueryCachingPolicy policy = new QueryCachingPolicy() { + @Override + public boolean shouldCache(Query query) throws IOException { + throw new UnsupportedOperationException(); + } + @Override + public void onUse(Query query) { + used[0] = true; + } + }; + policy = new ElasticsearchQueryCachingPolicy(policy); + policy.onUse(new TermQuery(new Term("foo", "bar"))); + assertFalse(used[0]); + policy.onUse(new PhraseQuery("foo", "bar", "baz")); + assertTrue(used[0]); + } + +} diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java index 29f77bc166a..73ca6eed48b 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java @@ -408,6 +408,9 @@ public abstract class ESIntegTestCase extends ESTestCase { if (randomBoolean()) { randomSettingsBuilder.put(IndexModule.INDEX_QUERY_CACHE_EVERYTHING_SETTING.getKey(), randomBoolean()); } + if (randomBoolean()) { + randomSettingsBuilder.put(IndexModule.INDEX_QUERY_CACHE_TERM_QUERIES_SETTING.getKey(), randomBoolean()); + } PutIndexTemplateRequestBuilder putTemplate = client().admin().indices() .preparePutTemplate("random_index_template") .setPatterns(Collections.singletonList("*")) From c6c734dce1c3770ab8b0fe9c69bcc3cda74dbe01 Mon Sep 17 00:00:00 2001 From: Colin Goodheart-Smithe Date: Wed, 16 Nov 2016 09:11:04 +0000 Subject: [PATCH 24/25] Fixes date range query using epoch with timezone (#21542) This change fixes the rnage query so that an exception is always thrown if the range query uses epoch time together with a time zone. Since epoch time is always UTC it should not be used with a time zone. Closes #21501 --- .../index/mapper/DateFieldMapper.java | 19 +++++++++++-------- .../index/mapper/DateFieldTypeTests.java | 7 +++++-- .../search/query/SearchQueryIT.java | 1 - 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java index cb2a1af9539..9c76d852883 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java @@ -321,14 +321,6 @@ public class DateFieldMapper extends FieldMapper { dateParser = this.dateMathParser; } - if (PointValues.size(reader, name()) == 0) { - // no points, so nothing matches - return Relation.DISJOINT; - } - - long minValue = LongPoint.decodeDimension(PointValues.getMinPackedValue(reader, name()), 0); - long maxValue = LongPoint.decodeDimension(PointValues.getMaxPackedValue(reader, name()), 0); - long fromInclusive = Long.MIN_VALUE; if (from != null) { fromInclusive = parseToMilliseconds(from, !includeLower, timeZone, dateParser, context); @@ -351,6 +343,17 @@ public class DateFieldMapper extends FieldMapper { } } + // This check needs to be done after fromInclusive and toInclusive + // are resolved so we can throw an exception if they are invalid + // even if there are no points in the shard + if (PointValues.size(reader, name()) == 0) { + // no points, so nothing matches + return Relation.DISJOINT; + } + + long minValue = LongPoint.decodeDimension(PointValues.getMinPackedValue(reader, name()), 0); + long maxValue = LongPoint.decodeDimension(PointValues.getMaxPackedValue(reader, name()), 0); + if (minValue >= fromInclusive && maxValue <= toInclusive) { return Relation.WITHIN; } else if (maxValue < fromInclusive || minValue > toInclusive) { diff --git a/core/src/test/java/org/elasticsearch/index/mapper/DateFieldTypeTests.java b/core/src/test/java/org/elasticsearch/index/mapper/DateFieldTypeTests.java index 12fd641724e..8ca6aeba30a 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/DateFieldTypeTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/DateFieldTypeTests.java @@ -73,11 +73,12 @@ public class DateFieldTypeTests extends FieldTypeTestCase { } public void testIsFieldWithinQueryEmptyReader() throws IOException { + QueryRewriteContext context = new QueryRewriteContext(null, null, null, null, null, null, null, () -> nowInMillis); IndexReader reader = new MultiReader(); DateFieldType ft = new DateFieldType(); ft.setName("my_date"); assertEquals(Relation.DISJOINT, ft.isFieldWithinQuery(reader, "2015-10-12", "2016-04-03", - randomBoolean(), randomBoolean(), null, null, null)); + randomBoolean(), randomBoolean(), null, null, context)); } private void doTestIsFieldWithinQuery(DateFieldType ft, DirectoryReader reader, @@ -128,7 +129,9 @@ public class DateFieldTypeTests extends FieldTypeTestCase { // Fields with no value indexed. DateFieldType ft2 = new DateFieldType(); ft2.setName("my_date2"); - assertEquals(Relation.DISJOINT, ft2.isFieldWithinQuery(reader, "2015-10-09", "2016-01-02", false, false, null, null, null)); + + QueryRewriteContext context = new QueryRewriteContext(null, null, null, null, null, null, null, () -> nowInMillis); + assertEquals(Relation.DISJOINT, ft2.isFieldWithinQuery(reader, "2015-10-09", "2016-01-02", false, false, null, null, context)); IOUtils.close(reader, w, dir); } diff --git a/core/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java b/core/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java index 311ddb7e3b4..71d258e1d7c 100644 --- a/core/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java +++ b/core/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java @@ -1904,7 +1904,6 @@ public class SearchQueryIT extends ESIntegTestCase { assertHitCount(client().prepareSearch("test").setSize(0).setQuery(rangeQuery("field").lte(-999999999999L)).get(), 3); } - @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/21501") public void testRangeQueryWithTimeZone() throws Exception { assertAcked(prepareCreate("test") .addMapping("type1", "date", "type=date", "num", "type=integer")); From 6baded8e7fb920e920a288bf53764a1da3d617da Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Wed, 16 Nov 2016 10:48:15 +0100 Subject: [PATCH 25/25] Remove dead code from GetResponse.java --- .../main/java/org/elasticsearch/action/get/GetResponse.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/action/get/GetResponse.java b/core/src/main/java/org/elasticsearch/action/get/GetResponse.java index 87cc42f9d27..ece7d06e0f3 100644 --- a/core/src/main/java/org/elasticsearch/action/get/GetResponse.java +++ b/core/src/main/java/org/elasticsearch/action/get/GetResponse.java @@ -164,12 +164,6 @@ public class GetResponse extends ActionResponse implements Iterable, T return getResult.toXContent(builder, params); } - public static GetResponse readGetResponse(StreamInput in) throws IOException { - GetResponse result = new GetResponse(); - result.readFrom(in); - return result; - } - @Override public void readFrom(StreamInput in) throws IOException { super.readFrom(in);