diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodeStats.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodeStats.java index 4cd050c7dda..d440eaddcee 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodeStats.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodeStats.java @@ -28,6 +28,7 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.discovery.DiscoveryStats; import org.elasticsearch.http.HttpStats; import org.elasticsearch.indices.NodeIndicesStats; import org.elasticsearch.indices.breaker.AllCircuitBreakerStats; @@ -78,6 +79,9 @@ public class NodeStats extends BaseNodeResponse implements ToXContent { @Nullable private ScriptStats scriptStats; + @Nullable + private DiscoveryStats discoveryStats; + NodeStats() { } @@ -85,7 +89,8 @@ public class NodeStats extends BaseNodeResponse implements ToXContent { @Nullable OsStats os, @Nullable ProcessStats process, @Nullable JvmStats jvm, @Nullable ThreadPoolStats threadPool, @Nullable FsInfo fs, @Nullable TransportStats transport, @Nullable HttpStats http, @Nullable AllCircuitBreakerStats breaker, - @Nullable ScriptStats scriptStats) { + @Nullable ScriptStats scriptStats, + @Nullable DiscoveryStats discoveryStats) { super(node); this.timestamp = timestamp; this.indices = indices; @@ -98,6 +103,7 @@ public class NodeStats extends BaseNodeResponse implements ToXContent { this.http = http; this.breaker = breaker; this.scriptStats = scriptStats; + this.discoveryStats = discoveryStats; } public long getTimestamp() { @@ -177,6 +183,11 @@ public class NodeStats extends BaseNodeResponse implements ToXContent { return this.scriptStats; } + @Nullable + public DiscoveryStats getDiscoveryStats() { + return this.discoveryStats; + } + public static NodeStats readNodeStats(StreamInput in) throws IOException { NodeStats nodeInfo = new NodeStats(); nodeInfo.readFrom(in); @@ -213,6 +224,7 @@ public class NodeStats extends BaseNodeResponse implements ToXContent { } breaker = AllCircuitBreakerStats.readOptionalAllCircuitBreakerStats(in); scriptStats = in.readOptionalStreamable(new ScriptStats()); + discoveryStats = in.readOptionalStreamable(new DiscoveryStats(null)); } @@ -270,6 +282,7 @@ public class NodeStats extends BaseNodeResponse implements ToXContent { } out.writeOptionalStreamable(breaker); out.writeOptionalStreamable(scriptStats); + out.writeOptionalStreamable(discoveryStats); } @Override @@ -321,6 +334,10 @@ public class NodeStats extends BaseNodeResponse implements ToXContent { getScriptStats().toXContent(builder, params); } + if (getDiscoveryStats() != null) { + getDiscoveryStats().toXContent(builder, params); + } + return builder; } } \ No newline at end of file diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodesStatsRequest.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodesStatsRequest.java index b0d7d7632fb..5916421c1ed 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodesStatsRequest.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodesStatsRequest.java @@ -41,6 +41,7 @@ public class NodesStatsRequest extends BaseNodesRequest<NodesStatsRequest> { private boolean http; private boolean breaker; private boolean script; + private boolean discovery; public NodesStatsRequest() { } @@ -67,6 +68,7 @@ public class NodesStatsRequest extends BaseNodesRequest<NodesStatsRequest> { this.http = true; this.breaker = true; this.script = true; + this.discovery = true; return this; } @@ -84,6 +86,7 @@ public class NodesStatsRequest extends BaseNodesRequest<NodesStatsRequest> { this.http = false; this.breaker = false; this.script = false; + this.discovery = false; return this; } @@ -234,6 +237,20 @@ public class NodesStatsRequest extends BaseNodesRequest<NodesStatsRequest> { return this; } + + public boolean discovery() { + return this.discovery; + } + + /** + * Should the node's discovery stats be returned. + */ + public NodesStatsRequest discovery(boolean discovery) { + this.discovery = discovery; + return this; + } + + @Override public void readFrom(StreamInput in) throws IOException { super.readFrom(in); @@ -247,6 +264,7 @@ public class NodesStatsRequest extends BaseNodesRequest<NodesStatsRequest> { http = in.readBoolean(); breaker = in.readBoolean(); script = in.readBoolean(); + discovery = in.readBoolean(); } @Override @@ -262,6 +280,7 @@ public class NodesStatsRequest extends BaseNodesRequest<NodesStatsRequest> { out.writeBoolean(http); out.writeBoolean(breaker); out.writeBoolean(script); + out.writeBoolean(discovery); } } diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodesStatsRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodesStatsRequestBuilder.java index dfa8007f7cf..dc35eefee7d 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodesStatsRequestBuilder.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodesStatsRequestBuilder.java @@ -19,7 +19,6 @@ package org.elasticsearch.action.admin.cluster.node.stats; -import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.admin.indices.stats.CommonStatsFlags; import org.elasticsearch.action.support.nodes.NodesOperationRequestBuilder; import org.elasticsearch.client.ElasticsearchClient; @@ -130,4 +129,12 @@ public class NodesStatsRequestBuilder extends NodesOperationRequestBuilder<Nodes request.http(http); return this; } + + /** + * Should the discovery stats be returned. + */ + public NodesStatsRequestBuilder setDiscovery(boolean discovery) { + request.discovery(discovery); + return this; + } } diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/TransportNodesStatsAction.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/TransportNodesStatsAction.java index 095819d1a5c..1660a6de4a1 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/TransportNodesStatsAction.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/TransportNodesStatsAction.java @@ -80,7 +80,7 @@ public class TransportNodesStatsAction extends TransportNodesAction<NodesStatsRe protected NodeStats nodeOperation(NodeStatsRequest nodeStatsRequest) { NodesStatsRequest request = nodeStatsRequest.request; return nodeService.stats(request.indices(), request.os(), request.process(), request.jvm(), request.threadPool(), - request.fs(), request.transport(), request.http(), request.breaker(), request.script()); + request.fs(), request.transport(), request.http(), request.breaker(), request.script(), request.discovery()); } @Override diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/stats/TransportClusterStatsAction.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/stats/TransportClusterStatsAction.java index cc2f17c433e..aeb76806713 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/stats/TransportClusterStatsAction.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/stats/TransportClusterStatsAction.java @@ -101,7 +101,7 @@ public class TransportClusterStatsAction extends TransportNodesAction<ClusterSta @Override protected ClusterStatsNodeResponse nodeOperation(ClusterStatsNodeRequest nodeRequest) { NodeInfo nodeInfo = nodeService.info(false, true, false, true, false, true, false, true); - NodeStats nodeStats = nodeService.stats(CommonStatsFlags.NONE, false, true, true, false, true, false, false, false, false); + NodeStats nodeStats = nodeService.stats(CommonStatsFlags.NONE, false, true, true, false, true, false, false, false, false, false); List<ShardStats> shardsStats = new ArrayList<>(); for (IndexService indexService : indicesService) { for (IndexShard indexShard : indexService) { diff --git a/core/src/main/java/org/elasticsearch/discovery/Discovery.java b/core/src/main/java/org/elasticsearch/discovery/Discovery.java index 13eb86f1ce4..980543d45e6 100644 --- a/core/src/main/java/org/elasticsearch/discovery/Discovery.java +++ b/core/src/main/java/org/elasticsearch/discovery/Discovery.java @@ -87,4 +87,10 @@ public interface Discovery extends LifecycleComponent<Discovery> { super(msg, cause, args); } } + + /** + * @return stats about the discovery + */ + DiscoveryStats stats(); + } diff --git a/core/src/main/java/org/elasticsearch/discovery/DiscoveryStats.java b/core/src/main/java/org/elasticsearch/discovery/DiscoveryStats.java new file mode 100644 index 00000000000..dcd75b07651 --- /dev/null +++ b/core/src/main/java/org/elasticsearch/discovery/DiscoveryStats.java @@ -0,0 +1,78 @@ +/* + * 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.discovery; + +import org.elasticsearch.common.Nullable; +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.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentBuilderString; +import org.elasticsearch.discovery.zen.publish.PendingClusterStateStats; + +import java.io.IOException; + +public class DiscoveryStats implements Streamable, ToXContent { + + @Nullable + private PendingClusterStateStats queueStats; + + public DiscoveryStats(PendingClusterStateStats queueStats) { + this.queueStats = queueStats; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(Fields.DISCOVERY); + + if (queueStats != null ){ + queueStats.toXContent(builder, params); + } + builder.endObject(); + return builder; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + if (in.readBoolean()) { + queueStats = new PendingClusterStateStats(); + queueStats.readFrom(in); + } + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + if (queueStats != null ) { + out.writeBoolean(true); + queueStats.writeTo(out); + }else{ + out.writeBoolean(false); + } + } + + static final class Fields { + static final XContentBuilderString DISCOVERY = new XContentBuilderString("discovery"); + } + + public PendingClusterStateStats getQueueStats() { + return queueStats; + } +} diff --git a/core/src/main/java/org/elasticsearch/discovery/local/LocalDiscovery.java b/core/src/main/java/org/elasticsearch/discovery/local/LocalDiscovery.java index 0979554b0c4..dd001294b97 100644 --- a/core/src/main/java/org/elasticsearch/discovery/local/LocalDiscovery.java +++ b/core/src/main/java/org/elasticsearch/discovery/local/LocalDiscovery.java @@ -316,6 +316,11 @@ public class LocalDiscovery extends AbstractLifecycleComponent<Discovery> implem } } + @Override + public DiscoveryStats stats() { + return new DiscoveryStats(null); + } + private LocalDiscovery[] members() { ClusterGroup clusterGroup = clusterGroups.get(clusterName); if (clusterGroup == null) { 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 9952f65a1b8..2b126a98ce2 100644 --- a/core/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java +++ b/core/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java @@ -43,6 +43,8 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.discovery.Discovery; import org.elasticsearch.discovery.DiscoverySettings; +import org.elasticsearch.discovery.DiscoveryStats; +import org.elasticsearch.discovery.zen.publish.PendingClusterStateStats; import org.elasticsearch.discovery.InitialStateDiscoveryListener; import org.elasticsearch.discovery.zen.elect.ElectMasterService; import org.elasticsearch.discovery.zen.fd.MasterFaultDetection; @@ -337,6 +339,12 @@ public class ZenDiscovery extends AbstractLifecycleComponent<Discovery> implemen } } + @Override + public DiscoveryStats stats() { + PendingClusterStateStats queueStats = publishClusterState.pendingStatesQueue().stats(); + return new DiscoveryStats(queueStats); + } + /** * returns true if zen discovery is started and there is a currently a background thread active for (re)joining * the cluster used for testing. diff --git a/core/src/main/java/org/elasticsearch/discovery/zen/publish/PendingClusterStateStats.java b/core/src/main/java/org/elasticsearch/discovery/zen/publish/PendingClusterStateStats.java new file mode 100644 index 00000000000..44265b0e481 --- /dev/null +++ b/core/src/main/java/org/elasticsearch/discovery/zen/publish/PendingClusterStateStats.java @@ -0,0 +1,97 @@ +/* + * 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.discovery.zen.publish; + +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.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentBuilderString; + +import java.io.IOException; + +/** + * Class encapsulating stats about the PendingClusterStatsQueue + */ +public class PendingClusterStateStats implements Streamable, ToXContent { + + private int total; + private int pending; + private int committed; + + public PendingClusterStateStats() { + + } + + public PendingClusterStateStats(int total, int pending, int committed) { + this.total = total; + this.pending = pending; + this.committed = committed; + } + + public int getCommitted() { + return committed; + } + + public int getPending() { + return pending; + } + + public int getTotal() { + return total; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(Fields.QUEUE); + builder.field(Fields.TOTAL, total); + builder.field(Fields.PENDING, pending); + builder.field(Fields.COMMITTED, committed); + builder.endObject(); + return builder; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + total = in.readVInt(); + pending = in.readVInt(); + committed = in.readVInt(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeVInt(total); + out.writeVInt(pending); + out.writeVInt(committed); + } + + static final class Fields { + static final XContentBuilderString QUEUE = new XContentBuilderString("cluster_state_queue"); + static final XContentBuilderString TOTAL = new XContentBuilderString("total"); + static final XContentBuilderString PENDING = new XContentBuilderString("pending"); + static final XContentBuilderString COMMITTED = new XContentBuilderString("committed"); + } + + @Override + public String toString() { + return "PendingClusterStateStats(total=" + total + ", pending=" + pending + ", committed=" + committed + ")"; + } +} diff --git a/core/src/main/java/org/elasticsearch/discovery/zen/publish/PendingClusterStatesQueue.java b/core/src/main/java/org/elasticsearch/discovery/zen/publish/PendingClusterStatesQueue.java index e3550e657fc..2f444f50288 100644 --- a/core/src/main/java/org/elasticsearch/discovery/zen/publish/PendingClusterStatesQueue.java +++ b/core/src/main/java/org/elasticsearch/discovery/zen/publish/PendingClusterStatesQueue.java @@ -283,4 +283,17 @@ public class PendingClusterStatesQueue { } } + public synchronized PendingClusterStateStats stats() { + + // calculate committed cluster state + int committed = 0; + for (ClusterStateContext clusterStatsContext : pendingStates) { + if (clusterStatsContext.committed()) { + committed += 1; + } + } + + return new PendingClusterStateStats(pendingStates.size(), pendingStates.size() - committed, committed); + } + } diff --git a/core/src/main/java/org/elasticsearch/node/service/NodeService.java b/core/src/main/java/org/elasticsearch/node/service/NodeService.java index fe57800a466..b4fe59e3473 100644 --- a/core/src/main/java/org/elasticsearch/node/service/NodeService.java +++ b/core/src/main/java/org/elasticsearch/node/service/NodeService.java @@ -152,13 +152,14 @@ public class NodeService extends AbstractComponent { transportService.stats(), httpServer == null ? null : httpServer.stats(), circuitBreakerService.stats(), - scriptService.stats() + scriptService.stats(), + discovery.stats() ); } public NodeStats stats(CommonStatsFlags indices, boolean os, boolean process, boolean jvm, boolean threadPool, boolean fs, boolean transport, boolean http, boolean circuitBreaker, - boolean script) { + boolean script, boolean discoveryStats) { // for indices stats we want to include previous allocated shards stats as well (it will // only be applied to the sensible ones to use, like refresh/merge/flush/indexing stats) return new NodeStats(discovery.localNode(), System.currentTimeMillis(), @@ -171,7 +172,8 @@ public class NodeService extends AbstractComponent { transport ? transportService.stats() : null, http ? (httpServer == null ? null : httpServer.stats()) : null, circuitBreaker ? circuitBreakerService.stats() : null, - script ? scriptService.stats() : null + script ? scriptService.stats() : null, + discoveryStats ? discovery.stats() : null ); } } diff --git a/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/node/stats/RestNodesStatsAction.java b/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/node/stats/RestNodesStatsAction.java index 2e3927e665e..910d3dcc833 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/node/stats/RestNodesStatsAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/node/stats/RestNodesStatsAction.java @@ -77,6 +77,7 @@ public class RestNodesStatsAction extends BaseRestHandler { nodesStatsRequest.process(metrics.contains("process")); nodesStatsRequest.breaker(metrics.contains("breaker")); nodesStatsRequest.script(metrics.contains("script")); + nodesStatsRequest.discovery(metrics.contains("discovery")); // check for index specific metrics if (metrics.contains("indices")) { diff --git a/core/src/test/java/org/elasticsearch/cluster/DiskUsageTests.java b/core/src/test/java/org/elasticsearch/cluster/DiskUsageTests.java index e48ca834f53..98eea13e673 100644 --- a/core/src/test/java/org/elasticsearch/cluster/DiskUsageTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/DiskUsageTests.java @@ -141,11 +141,11 @@ public class DiskUsageTests extends ESTestCase { }; NodeStats[] nodeStats = new NodeStats[] { new NodeStats(new DiscoveryNode("node_1", DummyTransportAddress.INSTANCE, Version.CURRENT), 0, - null,null,null,null,null,new FsInfo(0, node1FSInfo), null,null,null,null), + null,null,null,null,null,new FsInfo(0, node1FSInfo), null,null,null,null,null), new NodeStats(new DiscoveryNode("node_2", DummyTransportAddress.INSTANCE, Version.CURRENT), 0, - null,null,null,null,null, new FsInfo(0, node2FSInfo), null,null,null,null), + null,null,null,null,null, new FsInfo(0, node2FSInfo), null,null,null,null,null), new NodeStats(new DiscoveryNode("node_3", DummyTransportAddress.INSTANCE, Version.CURRENT), 0, - null,null,null,null,null, new FsInfo(0, node3FSInfo), null,null,null,null) + null,null,null,null,null, new FsInfo(0, node3FSInfo), null,null,null,null,null) }; InternalClusterInfoService.fillDiskUsagePerNode(logger, nodeStats, newLeastAvaiableUsages, newMostAvaiableUsages); DiskUsage leastNode_1 = newLeastAvaiableUsages.get("node_1"); diff --git a/core/src/test/java/org/elasticsearch/cluster/MockInternalClusterInfoService.java b/core/src/test/java/org/elasticsearch/cluster/MockInternalClusterInfoService.java index dd1cb0b9eff..6ac2101fe52 100644 --- a/core/src/test/java/org/elasticsearch/cluster/MockInternalClusterInfoService.java +++ b/core/src/test/java/org/elasticsearch/cluster/MockInternalClusterInfoService.java @@ -73,7 +73,7 @@ public class MockInternalClusterInfoService extends InternalClusterInfoService { null, null, null, null, null, fsInfo, null, null, null, - null); + null, null); } @Inject diff --git a/core/src/test/java/org/elasticsearch/discovery/DiscoveryModuleTests.java b/core/src/test/java/org/elasticsearch/discovery/DiscoveryModuleTests.java index f717102bce9..2a1b146da92 100644 --- a/core/src/test/java/org/elasticsearch/discovery/DiscoveryModuleTests.java +++ b/core/src/test/java/org/elasticsearch/discovery/DiscoveryModuleTests.java @@ -116,6 +116,11 @@ public class DiscoveryModuleTests extends ModuleTestCase { } + @Override + public DiscoveryStats stats() { + return null; + } + @Override public Lifecycle.State lifecycleState() { return null; diff --git a/core/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryIT.java b/core/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryIT.java index 11d94beac17..0b5f9997dba 100644 --- a/core/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryIT.java +++ b/core/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryIT.java @@ -22,6 +22,7 @@ package org.elasticsearch.discovery.zen; import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.Version; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; +import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse; import org.elasticsearch.action.admin.indices.recovery.RecoveryResponse; import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterService; @@ -34,7 +35,11 @@ import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.LocalTransportAddress; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.discovery.Discovery; +import org.elasticsearch.discovery.DiscoveryStats; import org.elasticsearch.discovery.zen.elect.ElectMasterService; import org.elasticsearch.discovery.zen.fd.FaultDetection; import org.elasticsearch.discovery.zen.membership.MembershipAction; @@ -256,4 +261,37 @@ public class ZenDiscoveryIT extends ESIntegTestCase { assertThat("Can't join master because version 1.6.0 is lower than the minimum compatable version 2.0.0 can support", electMasterService.electMaster(Collections.singletonList(node)), nullValue()); } + public void testDiscoveryStats() throws IOException { + String expectedStatsJsonResponse = "{\n" + + " \"discovery\" : {\n" + + " \"cluster_state_queue\" : {\n" + + " \"total\" : 0,\n" + + " \"pending\" : 0,\n" + + " \"committed\" : 0\n" + + " }\n" + + " }\n" + + "}"; + + Settings nodeSettings = Settings.settingsBuilder() + .put("discovery.type", "zen") // <-- To override the local setting if set externally + .build(); + internalCluster().startNode(nodeSettings); + + logger.info("--> request node discovery stats"); + NodesStatsResponse statsResponse = client().admin().cluster().prepareNodesStats().clear().setDiscovery(true).get(); + assertThat(statsResponse.getNodes().length, equalTo(1)); + + DiscoveryStats stats = statsResponse.getNodes()[0].getDiscoveryStats(); + assertThat(stats.getQueueStats(), notNullValue()); + assertThat(stats.getQueueStats().getTotal(), equalTo(0)); + assertThat(stats.getQueueStats().getCommitted(), equalTo(0)); + assertThat(stats.getQueueStats().getPending(), equalTo(0)); + + XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint(); + builder.startObject(); + stats.toXContent(builder, ToXContent.EMPTY_PARAMS); + builder.endObject(); + + assertThat(builder.string(), equalTo(expectedStatsJsonResponse)); + } } diff --git a/core/src/test/java/org/elasticsearch/discovery/zen/publish/PendingClusterStatesQueueTests.java b/core/src/test/java/org/elasticsearch/discovery/zen/publish/PendingClusterStatesQueueTests.java index a8e9f00eb7f..bc5e97ce08e 100644 --- a/core/src/test/java/org/elasticsearch/discovery/zen/publish/PendingClusterStatesQueueTests.java +++ b/core/src/test/java/org/elasticsearch/discovery/zen/publish/PendingClusterStatesQueueTests.java @@ -162,6 +162,31 @@ public class PendingClusterStatesQueueTests extends ESTestCase { } } + public void testQueueStats() { + List<ClusterState> states = randomStates(scaledRandomIntBetween(10, 100), "master"); + PendingClusterStatesQueue queue = createQueueWithStates(states); + assertThat(queue.stats().getTotal(), equalTo(states.size())); + assertThat(queue.stats().getPending(), equalTo(states.size())); + assertThat(queue.stats().getCommitted(), equalTo(0)); + + List<ClusterStateContext> committedContexts = randomCommitStates(queue); + assertThat(queue.stats().getTotal(), equalTo(states.size())); + assertThat(queue.stats().getPending(), equalTo(states.size() - committedContexts.size())); + assertThat(queue.stats().getCommitted(), equalTo(committedContexts.size())); + + ClusterState highestCommitted = null; + for (ClusterStateContext context : committedContexts) { + if (highestCommitted == null || context.state.supersedes(highestCommitted)) { + highestCommitted = context.state; + } + } + + queue.markAsProcessed(highestCommitted); + assertThat(queue.stats().getTotal(), equalTo(states.size() - committedContexts.size())); + assertThat(queue.stats().getPending(), equalTo(states.size() - committedContexts.size())); + assertThat(queue.stats().getCommitted(), equalTo(0)); + } + protected List<ClusterStateContext> randomCommitStates(PendingClusterStatesQueue queue) { List<ClusterStateContext> committedContexts = new ArrayList<>(); for (int iter = randomInt(queue.pendingStates.size() - 1); iter >= 0; iter--) { diff --git a/core/src/test/java/org/elasticsearch/test/InternalTestCluster.java b/core/src/test/java/org/elasticsearch/test/InternalTestCluster.java index 5e866125e96..6cafe4c3b79 100644 --- a/core/src/test/java/org/elasticsearch/test/InternalTestCluster.java +++ b/core/src/test/java/org/elasticsearch/test/InternalTestCluster.java @@ -1873,7 +1873,7 @@ public final class InternalTestCluster extends TestCluster { } NodeService nodeService = getInstanceFromNode(NodeService.class, nodeAndClient.node); - NodeStats stats = nodeService.stats(CommonStatsFlags.ALL, false, false, false, false, false, false, false, false, false); + NodeStats stats = nodeService.stats(CommonStatsFlags.ALL, false, false, false, false, false, false, false, false, false, false); assertThat("Fielddata size must be 0 on node: " + stats.getNode(), stats.getIndices().getFieldData().getMemorySizeInBytes(), equalTo(0l)); assertThat("Query cache size must be 0 on node: " + stats.getNode(), stats.getIndices().getQueryCache().getMemorySizeInBytes(), equalTo(0l)); assertThat("FixedBitSet cache size must be 0 on node: " + stats.getNode(), stats.getIndices().getSegments().getBitsetMemoryInBytes(), equalTo(0l)); diff --git a/docs/reference/cluster/nodes-stats.asciidoc b/docs/reference/cluster/nodes-stats.asciidoc index b22312e2130..9890164bff5 100644 --- a/docs/reference/cluster/nodes-stats.asciidoc +++ b/docs/reference/cluster/nodes-stats.asciidoc @@ -57,6 +57,9 @@ of `indices`, `os`, `process`, `jvm`, `transport`, `http`, `breaker`:: Statistics about the field data circuit breaker +`discovery`:: + Statistics about the discovery + [source,js] -------------------------------------------------- # return indices and os diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/nodes.stats.json b/rest-api-spec/src/main/resources/rest-api-spec/api/nodes.stats.json index 874294102c7..fb9ef094f0b 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/nodes.stats.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/nodes.stats.json @@ -15,7 +15,7 @@ "parts": { "metric" : { "type" : "list", - "options" : ["_all", "breaker", "fs", "http", "indices", "jvm", "os", "process", "thread_pool", "transport"], + "options" : ["_all", "breaker", "fs", "http", "indices", "jvm", "os", "process", "thread_pool", "transport", "discovery"], "description" : "Limit the information returned to the specified metrics" }, "index_metric" : { diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/30_discovery.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/30_discovery.yaml new file mode 100644 index 00000000000..a0fb566f893 --- /dev/null +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/30_discovery.yaml @@ -0,0 +1,25 @@ +--- +"Discovery stats": + - do: + cluster.state: {} + + # Get master node id + - set: { master_node: master } + + - do: + nodes.stats: + metric: [ discovery ] + + - is_true: cluster_name + - is_true: nodes + - is_true: nodes.$master.discovery + + - do: + nodes.stats: + filter_path: "nodes.*.discovery" + + - is_false: cluster_name + - is_true: nodes + - is_false: nodes.$master.name + - is_false: nodes.$master.jvm + - is_true: nodes.$master.discovery