/* * 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.cluster.stats; import com.carrotsearch.hppc.ObjectObjectHashMap; import com.carrotsearch.hppc.cursors.ObjectObjectCursor; import org.elasticsearch.action.admin.indices.stats.CommonStats; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.cache.query.QueryCacheStats; import org.elasticsearch.index.engine.SegmentsStats; import org.elasticsearch.index.fielddata.FieldDataStats; import org.elasticsearch.index.shard.DocsStats; import org.elasticsearch.index.store.StoreStats; import org.elasticsearch.search.suggest.completion.CompletionStats; import java.io.IOException; import java.util.List; public class ClusterStatsIndices implements ToXContent { private int indexCount; private ShardStats shards; private DocsStats docs; private StoreStats store; private FieldDataStats fieldData; private QueryCacheStats queryCache; private CompletionStats completion; private SegmentsStats segments; public ClusterStatsIndices(List<ClusterStatsNodeResponse> nodeResponses) { ObjectObjectHashMap<String, ShardStats> countsPerIndex = new ObjectObjectHashMap<>(); this.docs = new DocsStats(); this.store = new StoreStats(); this.fieldData = new FieldDataStats(); this.queryCache = new QueryCacheStats(); this.completion = new CompletionStats(); this.segments = new SegmentsStats(); for (ClusterStatsNodeResponse r : nodeResponses) { for (org.elasticsearch.action.admin.indices.stats.ShardStats shardStats : r.shardsStats()) { ShardStats indexShardStats = countsPerIndex.get(shardStats.getShardRouting().getIndexName()); if (indexShardStats == null) { indexShardStats = new ShardStats(); countsPerIndex.put(shardStats.getShardRouting().getIndexName(), indexShardStats); } indexShardStats.total++; CommonStats shardCommonStats = shardStats.getStats(); if (shardStats.getShardRouting().primary()) { indexShardStats.primaries++; docs.add(shardCommonStats.docs); } store.add(shardCommonStats.store); fieldData.add(shardCommonStats.fieldData); queryCache.add(shardCommonStats.queryCache); completion.add(shardCommonStats.completion); segments.add(shardCommonStats.segments); } } shards = new ShardStats(); indexCount = countsPerIndex.size(); for (ObjectObjectCursor<String, ShardStats> indexCountsCursor : countsPerIndex) { shards.addIndexShardCount(indexCountsCursor.value); } } public int getIndexCount() { return indexCount; } public ShardStats getShards() { return this.shards; } public DocsStats getDocs() { return docs; } public StoreStats getStore() { return store; } public FieldDataStats getFieldData() { return fieldData; } public QueryCacheStats getQueryCache() { return queryCache; } public CompletionStats getCompletion() { return completion; } public SegmentsStats getSegments() { return segments; } static final class Fields { static final String COUNT = "count"; } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.field(Fields.COUNT, indexCount); shards.toXContent(builder, params); docs.toXContent(builder, params); store.toXContent(builder, params); fieldData.toXContent(builder, params); queryCache.toXContent(builder, params); completion.toXContent(builder, params); segments.toXContent(builder, params); return builder; } public static class ShardStats implements ToXContent { int indices; int total; int primaries; // min/max int minIndexShards = -1; int maxIndexShards = -1; int minIndexPrimaryShards = -1; int maxIndexPrimaryShards = -1; double minIndexReplication = -1; double totalIndexReplication = 0; double maxIndexReplication = -1; public ShardStats() { } /** * number of indices in the cluster */ public int getIndices() { return this.indices; } /** * total number of shards in the cluster */ public int getTotal() { return this.total; } /** * total number of primary shards in the cluster */ public int getPrimaries() { return this.primaries; } /** * returns how many *redundant* copies of the data the cluster holds - running with no replicas will return 0 */ public double getReplication() { if (primaries == 0) { return 0; } return (((double) (total - primaries)) / primaries); } /** * the maximum number of shards (primary+replicas) an index has */ public int getMaxIndexShards() { return this.maxIndexShards; } /** * the minimum number of shards (primary+replicas) an index has */ public int getMinIndexShards() { return this.minIndexShards; } /** * average number of shards (primary+replicas) across the indices */ public double getAvgIndexShards() { if (this.indices == 0) { return -1; } return ((double) this.total) / this.indices; } /** * the maximum number of primary shards an index has */ public int getMaxIndexPrimaryShards() { return this.maxIndexPrimaryShards; } /** * the minimum number of primary shards an index has */ public int getMinIndexPrimaryShards() { return this.minIndexPrimaryShards; } /** * the average number primary shards across the indices */ public double getAvgIndexPrimaryShards() { if (this.indices == 0) { return -1; } return ((double) this.primaries) / this.indices; } /** * minimum replication factor across the indices. See {@link #getReplication} */ public double getMinIndexReplication() { return this.minIndexReplication; } /** * average replication factor across the indices. See {@link #getReplication} */ public double getAvgIndexReplication() { if (indices == 0) { return -1; } return this.totalIndexReplication / this.indices; } /** * maximum replication factor across the indices. See {@link #getReplication} */ public double getMaxIndexReplication() { return this.maxIndexReplication; } public void addIndexShardCount(ShardStats indexShardCount) { this.indices++; this.primaries += indexShardCount.primaries; this.total += indexShardCount.total; this.totalIndexReplication += indexShardCount.getReplication(); if (this.indices == 1) { // first index, uninitialized. minIndexPrimaryShards = indexShardCount.primaries; maxIndexPrimaryShards = indexShardCount.primaries; minIndexShards = indexShardCount.total; maxIndexShards = indexShardCount.total; minIndexReplication = indexShardCount.getReplication(); maxIndexReplication = minIndexReplication; } else { minIndexShards = Math.min(minIndexShards, indexShardCount.total); minIndexPrimaryShards = Math.min(minIndexPrimaryShards, indexShardCount.primaries); minIndexReplication = Math.min(minIndexReplication, indexShardCount.getReplication()); maxIndexShards = Math.max(maxIndexShards, indexShardCount.total); maxIndexPrimaryShards = Math.max(maxIndexPrimaryShards, indexShardCount.primaries); maxIndexReplication = Math.max(maxIndexReplication, indexShardCount.getReplication()); } } static final class Fields { static final String SHARDS = "shards"; static final String TOTAL = "total"; static final String PRIMARIES = "primaries"; static final String REPLICATION = "replication"; static final String MIN = "min"; static final String MAX = "max"; static final String AVG = "avg"; static final String INDEX = "index"; } private void addIntMinMax(String field, int min, int max, double avg, XContentBuilder builder) throws IOException { builder.startObject(field); builder.field(Fields.MIN, min); builder.field(Fields.MAX, max); builder.field(Fields.AVG, avg); builder.endObject(); } private void addDoubleMinMax(String field, double min, double max, double avg, XContentBuilder builder) throws IOException { builder.startObject(field); builder.field(Fields.MIN, min); builder.field(Fields.MAX, max); builder.field(Fields.AVG, avg); builder.endObject(); } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(Fields.SHARDS); if (indices > 0) { builder.field(Fields.TOTAL, total); builder.field(Fields.PRIMARIES, primaries); builder.field(Fields.REPLICATION, getReplication()); builder.startObject(Fields.INDEX); addIntMinMax(Fields.SHARDS, minIndexShards, maxIndexShards, getAvgIndexShards(), builder); addIntMinMax(Fields.PRIMARIES, minIndexPrimaryShards, maxIndexPrimaryShards, getAvgIndexPrimaryShards(), builder); addDoubleMinMax(Fields.REPLICATION, minIndexReplication, maxIndexReplication, getAvgIndexReplication(), builder); builder.endObject(); } builder.endObject(); return builder; } @Override public String toString() { return "total [" + total + "] primaries [" + primaries + "]"; } } }