/*
* 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.document;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.indices.recovery.RecoveryResponse;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.test.ESIntegTestCase;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
public class ShardInfoIT extends ESIntegTestCase {
private int numCopies;
private int numNodes;
public void testIndexAndDelete() throws Exception {
prepareIndex(1);
IndexResponse indexResponse = client().prepareIndex("idx", "type").setSource("{}", XContentType.JSON).get();
assertShardInfo(indexResponse);
DeleteResponse deleteResponse = client().prepareDelete("idx", "type", indexResponse.getId()).get();
assertShardInfo(deleteResponse);
}
public void testUpdate() throws Exception {
prepareIndex(1);
UpdateResponse updateResponse = client().prepareUpdate("idx", "type", "1").setDoc("{}", XContentType.JSON).setDocAsUpsert(true)
.get();
assertShardInfo(updateResponse);
}
public void testBulkWithIndexAndDeleteItems() throws Exception {
prepareIndex(1);
BulkRequestBuilder bulkRequestBuilder = client().prepareBulk();
for (int i = 0; i < 10; i++) {
bulkRequestBuilder.add(client().prepareIndex("idx", "type").setSource("{}", XContentType.JSON));
}
BulkResponse bulkResponse = bulkRequestBuilder.get();
bulkRequestBuilder = client().prepareBulk();
for (BulkItemResponse item : bulkResponse) {
assertThat(item.isFailed(), equalTo(false));
assertShardInfo(item.getResponse());
bulkRequestBuilder.add(client().prepareDelete("idx", "type", item.getId()));
}
bulkResponse = bulkRequestBuilder.get();
for (BulkItemResponse item : bulkResponse) {
assertThat(item.isFailed(), equalTo(false));
assertShardInfo(item.getResponse());
}
}
public void testBulkWithUpdateItems() throws Exception {
prepareIndex(1);
BulkRequestBuilder bulkRequestBuilder = client().prepareBulk();
for (int i = 0; i < 10; i++) {
bulkRequestBuilder.add(client().prepareUpdate("idx", "type", Integer.toString(i)).setDoc("{}", XContentType.JSON)
.setDocAsUpsert(true));
}
BulkResponse bulkResponse = bulkRequestBuilder.get();
for (BulkItemResponse item : bulkResponse) {
assertThat(item.isFailed(), equalTo(false));
assertShardInfo(item.getResponse());
}
}
private void prepareIndex(int numberOfPrimaryShards) throws Exception {
prepareIndex(numberOfPrimaryShards, false);
}
private void prepareIndex(int numberOfPrimaryShards, boolean routingRequired) throws Exception {
numNodes = cluster().numDataNodes();
logger.info("Number of nodes: {}", numNodes);
int maxNumberOfCopies = (numNodes * 2) - 1;
numCopies = randomIntBetween(numNodes, maxNumberOfCopies);
logger.info("Number of copies: {}", numCopies);
assertAcked(prepareCreate("idx").setSettings(
Settings.builder()
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, numberOfPrimaryShards)
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, numCopies - 1))
.addMapping("type", "_routing", "required=" + routingRequired)
.get());
for (int i = 0; i < numberOfPrimaryShards; i++) {
ensureActiveShardCopies(i, numNodes);
}
}
private void assertShardInfo(ReplicationResponse response) {
assertShardInfo(response, numCopies, numNodes);
}
private void assertShardInfo(ReplicationResponse response, int expectedTotal, int expectedSuccessful) {
assertThat(response.getShardInfo().getTotal(), greaterThanOrEqualTo(expectedTotal));
assertThat(response.getShardInfo().getSuccessful(), greaterThanOrEqualTo(expectedSuccessful));
}
private void ensureActiveShardCopies(final int shardId, final int copyCount) throws Exception {
assertBusy(new Runnable() {
@Override
public void run() {
ClusterState state = client().admin().cluster().prepareState().get().getState();
assertThat(state.routingTable().index("idx"), not(nullValue()));
assertThat(state.routingTable().index("idx").shard(shardId), not(nullValue()));
assertThat(state.routingTable().index("idx").shard(shardId).activeShards().size(), equalTo(copyCount));
ClusterHealthResponse healthResponse = client().admin().cluster().prepareHealth("idx")
.setWaitForNoRelocatingShards(true)
.get();
assertThat(healthResponse.isTimedOut(), equalTo(false));
RecoveryResponse recoveryResponse = client().admin().indices().prepareRecoveries("idx")
.setActiveOnly(true)
.get();
assertThat(recoveryResponse.shardRecoveryStates().get("idx").size(), equalTo(0));
}
});
}
}