Add the 'recovery' _cat API endpoint

This addes the _cat/recovery/{index} API endpoint, which displays
information about the status of recovering shards. An example of the
output:

index shard node                   target    recovered     %
test2 0     Fwo7c_6MSdWM0uM1Ho4t-g 147304414  19236101 13.1%
test  0     Fwo7c_6MSdWM0uM1Ho4t-g 145891423 119640535 82.0%

Fixes #3969
This commit is contained in:
Lee Hinman 2013-10-28 13:43:02 -06:00
parent b1b52b641d
commit e3db12bf50
2 changed files with 149 additions and 5 deletions

View File

@ -69,10 +69,7 @@ import org.elasticsearch.rest.action.admin.indices.warmer.delete.RestDeleteWarme
import org.elasticsearch.rest.action.admin.indices.warmer.get.RestGetWarmerAction;
import org.elasticsearch.rest.action.admin.indices.warmer.put.RestPutWarmerAction;
import org.elasticsearch.rest.action.bulk.RestBulkAction;
import org.elasticsearch.rest.action.cat.RestIndicesAction;
import org.elasticsearch.rest.action.cat.RestMasterAction;
import org.elasticsearch.rest.action.cat.RestNodesAction;
import org.elasticsearch.rest.action.cat.RestShardsAction;
import org.elasticsearch.rest.action.cat.*;
import org.elasticsearch.rest.action.count.RestCountAction;
import org.elasticsearch.rest.action.delete.RestDeleteAction;
import org.elasticsearch.rest.action.deletebyquery.RestDeleteByQueryAction;
@ -200,6 +197,7 @@ public class RestActionModule extends AbstractModule {
bind(RestIndicesAction.class).asEagerSingleton();
// Fully qualified to prevent interference with rest.action.count.RestCountAction
bind(org.elasticsearch.rest.action.cat.RestCountAction.class).asEagerSingleton();
bind(RestClearScrollAction.class).asEagerSingleton();;
bind(RestClearScrollAction.class).asEagerSingleton();
bind(RestRecoveryAction.class).asEagerSingleton();
}
}

View File

@ -0,0 +1,146 @@
/*
* Licensed to ElasticSearch and Shay Banon 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.cat;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.status.IndicesStatusRequest;
import org.elasticsearch.action.admin.indices.status.IndicesStatusResponse;
import org.elasticsearch.action.admin.indices.status.ShardStatus;
import org.elasticsearch.action.support.broadcast.BroadcastOperationThreading;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.Table;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.shard.IndexShardState;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestTable;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static org.elasticsearch.rest.RestRequest.Method.GET;
/**
* RestRecoveryAction provides information about the status of replica recovery
* in a string format, designed to be used at the command line. An Index can
* be specified to limit output to a particular index or indices.
*/
public class RestRecoveryAction extends BaseRestHandler {
@Inject
protected RestRecoveryAction(Settings settings, Client client, RestController restController) {
super(settings, client);
restController.registerHandler(GET, "/_cat/recovery", this);
restController.registerHandler(GET, "/_cat/recovery/{index}", this);
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel) {
String[] indices = Strings.splitStringByCommaToArray(request.param("index"));
IndicesStatusRequest indicesStatusRequest = new IndicesStatusRequest(indices);
indicesStatusRequest.recovery(true);
indicesStatusRequest.operationThreading(BroadcastOperationThreading.SINGLE_THREAD);
client.admin().indices().status(indicesStatusRequest, new ActionListener<IndicesStatusResponse>() {
@Override
public void onResponse(IndicesStatusResponse indicesStatusResponse) {
Map<String, Long> primarySizes = new HashMap<String, Long>();
Set<ShardStatus> replicas = new HashSet<ShardStatus>();
// Loop through all the shards in the index status, keeping
// track of the primary shard size with a Map and the
// recovering shards in a Set of ShardStatus objects
for (ShardStatus shardStatus : indicesStatusResponse.getShards()) {
if (shardStatus.getShardRouting().primary()) {
primarySizes.put(shardStatus.getShardRouting().getIndex() + shardStatus.getShardRouting().getId(),
shardStatus.getStoreSize().bytes());
} else if (shardStatus.getState() == IndexShardState.RECOVERING) {
replicas.add(shardStatus);
}
}
try {
channel.sendResponse(RestTable.buildResponse(buildRecoveryTable(primarySizes, replicas), request, channel));
} catch (Throwable e) {
try {
channel.sendResponse(new XContentThrowableRestResponse(request, e));
} catch (IOException e2) {
logger.error("Unable to send recovery status response", e2);
}
}
}
@Override
public void onFailure(Throwable e) {
try {
channel.sendResponse(new XContentThrowableRestResponse(request, e));
} catch (IOException e1) {
logger.error("Failed to send failure response", e1);
}
}
});
}
/**
* buildRecoveryTable will build a table of recovery information suitable
* for displaying at the command line.
* @param primarySizes A Map of {@code index + shardId} strings to store size for all primary shards.
* @param recoveringReplicas A Set of {@link ShardStatus} objects for each recovering replica to be displayed.
* @return A table containing index, shardId, node, target size, recovered size and percentage for each recovering replica
*/
public static Table buildRecoveryTable(Map<String, Long> primarySizes, Set<ShardStatus> recoveringReplicas) {
Table t = new Table();
t.startHeaders().addCell("index")
.addCell("shard")
.addCell("node")
.addCell("target", "text-align:right;")
.addCell("recovered", "text-align:right;")
.addCell("%", "text-align:right;")
.endHeaders();
for (ShardStatus status : recoveringReplicas) {
String index = status.getShardRouting().getIndex();
int id = status.getShardId();
long replicaSize = status.getStoreSize().bytes();
Long primarySize = primarySizes.get(index + id);
t.startRow();
t.addCell(index);
t.addCell(id);
t.addCell(status.getShardRouting().currentNodeId());
if (primarySize == null) {
t.addCell("NaN");
} else {
t.addCell(primarySize);
}
t.addCell(replicaSize);
if (primarySize == null) {
t.addCell("NaN");
} else {
t.addCell(String.format("%1.1f%%", 100.0 * (float)replicaSize / primarySize));
}
t.endRow();
}
return t;
}
}