ActiveShardCount should not fail when closing the index (#35936)

The ActiveShardCount is used by cluster state observers to wait for a 
given number of shards to be active before returning to the caller. The 
current implementation does not work when an index is closed while an 
observer is waiting on shards to be active. In this case, a NPE is thrown 
and the observer is never notified that the shards won't become active.

This commit fixes the ActiveShardCount.enoughShardsActive() so that it 
does not fail when an index is closed, similarly to what is done when an 
index is deleted.
This commit is contained in:
Tanguy Leroux 2018-11-29 09:08:30 +01:00 committed by GitHub
parent 45db829039
commit 0967620641
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 0 deletions

View File

@ -156,6 +156,12 @@ public final class ActiveShardCount implements Writeable {
continue; continue;
} }
final IndexRoutingTable indexRoutingTable = clusterState.routingTable().index(indexName); final IndexRoutingTable indexRoutingTable = clusterState.routingTable().index(indexName);
if (indexRoutingTable == null && indexMetaData.getState() == IndexMetaData.State.CLOSE) {
// its possible the index was closed while waiting for active shard copies,
// in this case, we'll just consider it that we have enough active shard copies
// and we can stop waiting
continue;
}
assert indexRoutingTable != null; assert indexRoutingTable != null;
if (indexRoutingTable.allPrimaryShardsActive() == false) { if (indexRoutingTable.allPrimaryShardsActive() == false) {
// all primary shards aren't active yet // all primary shards aren't active yet

View File

@ -36,6 +36,7 @@ import org.elasticsearch.test.ESTestCase;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays;
/** /**
* Tests for the {@link ActiveShardCount} class * Tests for the {@link ActiveShardCount} class
@ -165,6 +166,17 @@ public class ActiveShardCountTests extends ESTestCase {
assertEquals("activeShardCount cannot be negative", e.getMessage()); assertEquals("activeShardCount cannot be negative", e.getMessage());
} }
public void testEnoughShardsActiveWithClosedIndex() {
final String indexName = "test-idx";
final int numberOfShards = randomIntBetween(1, 5);
final int numberOfReplicas = randomIntBetween(4, 7);
final ClusterState clusterState = initializeWithClosedIndex(indexName, numberOfShards, numberOfReplicas);
for (ActiveShardCount waitForActiveShards : Arrays.asList(ActiveShardCount.DEFAULT, ActiveShardCount.ALL, ActiveShardCount.ONE)) {
assertTrue(waitForActiveShards.enoughShardsActive(clusterState, indexName));
}
}
private void runTestForOneActiveShard(final ActiveShardCount activeShardCount) { private void runTestForOneActiveShard(final ActiveShardCount activeShardCount) {
final String indexName = "test-idx"; final String indexName = "test-idx";
final int numberOfShards = randomIntBetween(1, 5); final int numberOfShards = randomIntBetween(1, 5);
@ -192,6 +204,18 @@ public class ActiveShardCountTests extends ESTestCase {
return ClusterState.builder(new ClusterName("test_cluster")).metaData(metaData).routingTable(routingTable).build(); return ClusterState.builder(new ClusterName("test_cluster")).metaData(metaData).routingTable(routingTable).build();
} }
private ClusterState initializeWithClosedIndex(final String indexName, final int numShards, final int numReplicas) {
final IndexMetaData indexMetaData = IndexMetaData.builder(indexName)
.settings(settings(Version.CURRENT)
.put(IndexMetaData.SETTING_INDEX_UUID, UUIDs.randomBase64UUID()))
.numberOfShards(numShards)
.numberOfReplicas(numReplicas)
.state(IndexMetaData.State.CLOSE)
.build();
final MetaData metaData = MetaData.builder().put(indexMetaData, true).build();
return ClusterState.builder(new ClusterName("test_cluster")).metaData(metaData).build();
}
private ClusterState startPrimaries(final ClusterState clusterState, final String indexName) { private ClusterState startPrimaries(final ClusterState clusterState, final String indexName) {
RoutingTable routingTable = clusterState.routingTable(); RoutingTable routingTable = clusterState.routingTable();
IndexRoutingTable indexRoutingTable = routingTable.index(indexName); IndexRoutingTable indexRoutingTable = routingTable.index(indexName);