From 02cc73017081d29d86a42d1c81b5a26720a91756 Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Mon, 4 Feb 2019 14:19:52 +0100 Subject: [PATCH] Allow shards of closed indices to be replicated as regular shards (#38024) This commit allows shards of indices in CLOSE state to be replicated as normal shards. It changes the MetaDataIndexStateService so that index routing tables of closed indices are kept in cluster state when the index is closed. Index routing tables are modified so that shard routings are reinitialized with the INDEX_CLOSED unassigned information. The IndicesClusterStateService is modified to remove IndexService instances of closed or reopened indices. In combination with the ShardRouting being in INITIALIZING state the shards are recreated on the data nodes to reflect the new state. If the index state is closed, the IndexShard instances will be created using the NoOpEngine as the engine implementation. This commit also mutes two tests that rely on the fact that shard locks are released when an index is closed, which is not the case anymore with replicated closed indices (actually the locks are released but reacquired once the shard is reinitialized after being closed). These tests will be adapted in follow up PRs. Finally, many things will require to be adapted or improved in follow up PRs (see #33888) but this is the first big step towards replicated closed indices. Relates to #33888 --- .../metadata/MetaDataIndexStateService.java | 6 ++- .../cluster/routing/IndexRoutingTable.java | 7 +++ .../cluster/routing/RoutingTable.java | 7 +++ .../cluster/routing/UnassignedInfo.java | 8 +++- .../index/engine/NoOpEngine.java | 3 +- .../cluster/IndicesClusterStateService.java | 47 ++++++++++++------- .../elasticsearch/search/SearchService.java | 2 +- .../MetaDataIndexStateServiceTests.java | 41 +++++++++++----- .../cluster/routing/UnassignedInfoTests.java | 20 +++++++- .../gateway/GatewayIndexStateIT.java | 16 ++++--- .../index/shard/IndexShardIT.java | 20 +++----- .../indices/IndicesServiceTests.java | 2 + .../indices/state/CloseIndexIT.java | 3 +- .../indices/state/SimpleIndexStateIT.java | 4 +- .../search/scroll/SearchScrollIT.java | 11 ++--- .../SharedClusterSnapshotRestoreIT.java | 4 +- 16 files changed, 132 insertions(+), 69 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/MetaDataIndexStateService.java b/server/src/main/java/org/elasticsearch/cluster/metadata/MetaDataIndexStateService.java index 0781cab1fe757..3e9143320c53c 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/MetaDataIndexStateService.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/MetaDataIndexStateService.java @@ -410,14 +410,16 @@ static ClusterState closeRoutingTable(final ClusterState currentState, } logger.debug("closing index {} succeeded", index); - blocks.removeIndexBlockWithId(index.getName(), INDEX_CLOSED_BLOCK_ID).addIndexBlock(index.getName(), INDEX_CLOSED_BLOCK); metadata.put(IndexMetaData.builder(indexMetaData).state(IndexMetaData.State.CLOSE)); - routingTable.remove(index.getName()); + blocks.removeIndexBlockWithId(index.getName(), INDEX_CLOSED_BLOCK_ID); + blocks.addIndexBlock(index.getName(), INDEX_CLOSED_BLOCK); + routingTable.addAsFromOpenToClose(metadata.getSafe(index)); closedIndices.add(index.getName()); } catch (final IndexNotFoundException e) { logger.debug("index {} has been deleted since it was blocked before closing, ignoring", index); } } + logger.info("completed closing of indices {}", closedIndices); return ClusterState.builder(currentState).blocks(blocks).metaData(metadata).routingTable(routingTable.build()).build(); } diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/IndexRoutingTable.java b/server/src/main/java/org/elasticsearch/cluster/routing/IndexRoutingTable.java index cf1235c8f2158..195ae2cce25b8 100644 --- a/server/src/main/java/org/elasticsearch/cluster/routing/IndexRoutingTable.java +++ b/server/src/main/java/org/elasticsearch/cluster/routing/IndexRoutingTable.java @@ -358,6 +358,13 @@ public Builder initializeAsFromCloseToOpen(IndexMetaData indexMetaData) { return initializeEmpty(indexMetaData, new UnassignedInfo(UnassignedInfo.Reason.INDEX_REOPENED, null)); } + /** + * Initializes a new empty index, as as a result of closing an opened index. + */ + public Builder initializeAsFromOpenToClose(IndexMetaData indexMetaData) { + return initializeEmpty(indexMetaData, new UnassignedInfo(UnassignedInfo.Reason.INDEX_CLOSED, null)); + } + /** * Initializes a new empty index, to be restored from a snapshot */ diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/RoutingTable.java b/server/src/main/java/org/elasticsearch/cluster/routing/RoutingTable.java index 0d5ee132ffa9b..0c6080029895b 100644 --- a/server/src/main/java/org/elasticsearch/cluster/routing/RoutingTable.java +++ b/server/src/main/java/org/elasticsearch/cluster/routing/RoutingTable.java @@ -540,6 +540,13 @@ public Builder addAsFromCloseToOpen(IndexMetaData indexMetaData) { return this; } + public Builder addAsFromOpenToClose(IndexMetaData indexMetaData) { + assert indexMetaData.getState() == IndexMetaData.State.CLOSE; + IndexRoutingTable.Builder indexRoutingBuilder = new IndexRoutingTable.Builder(indexMetaData.getIndex()) + .initializeAsFromOpenToClose(indexMetaData); + return add(indexRoutingBuilder); + } + public Builder addAsRestore(IndexMetaData indexMetaData, SnapshotRecoverySource recoverySource) { IndexRoutingTable.Builder indexRoutingBuilder = new IndexRoutingTable.Builder(indexMetaData.getIndex()) .initializeAsRestore(indexMetaData, recoverySource); diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/UnassignedInfo.java b/server/src/main/java/org/elasticsearch/cluster/routing/UnassignedInfo.java index f8afbeb449361..ec7b053764afc 100644 --- a/server/src/main/java/org/elasticsearch/cluster/routing/UnassignedInfo.java +++ b/server/src/main/java/org/elasticsearch/cluster/routing/UnassignedInfo.java @@ -118,7 +118,11 @@ public enum Reason { /** * Forced manually to allocate */ - MANUAL_ALLOCATION + MANUAL_ALLOCATION, + /** + * Unassigned as a result of closing an index. + */ + INDEX_CLOSED } /** @@ -269,6 +273,8 @@ public UnassignedInfo(StreamInput in) throws IOException { public void writeTo(StreamOutput out) throws IOException { if (out.getVersion().before(Version.V_6_0_0_beta2) && reason == Reason.MANUAL_ALLOCATION) { out.writeByte((byte) Reason.ALLOCATION_FAILED.ordinal()); + } else if (out.getVersion().before(Version.V_7_0_0) && reason == Reason.INDEX_CLOSED) { + out.writeByte((byte) Reason.REINITIALIZED.ordinal()); } else { out.writeByte((byte) reason.ordinal()); } diff --git a/server/src/main/java/org/elasticsearch/index/engine/NoOpEngine.java b/server/src/main/java/org/elasticsearch/index/engine/NoOpEngine.java index 8eec141975312..fe1ad7a1a144f 100644 --- a/server/src/main/java/org/elasticsearch/index/engine/NoOpEngine.java +++ b/server/src/main/java/org/elasticsearch/index/engine/NoOpEngine.java @@ -44,8 +44,7 @@ public NoOpEngine(EngineConfig config) { protected DirectoryReader open(final IndexCommit commit) throws IOException { final Directory directory = commit.getDirectory(); final List indexCommits = DirectoryReader.listCommits(directory); - assert indexCommits.size() == 1 : "expected only one commit point"; - IndexCommit indexCommit = indexCommits.get(indexCommits.size() - 1); + final IndexCommit indexCommit = indexCommits.get(indexCommits.size() - 1); return new DirectoryReader(directory, new LeafReader[0]) { @Override protected DirectoryReader doOpenIfChanged() throws IOException { diff --git a/server/src/main/java/org/elasticsearch/indices/cluster/IndicesClusterStateService.java b/server/src/main/java/org/elasticsearch/indices/cluster/IndicesClusterStateService.java index 57ec87d1c6493..c0fbd1272b973 100644 --- a/server/src/main/java/org/elasticsearch/indices/cluster/IndicesClusterStateService.java +++ b/server/src/main/java/org/elasticsearch/indices/cluster/IndicesClusterStateService.java @@ -98,6 +98,7 @@ import static org.elasticsearch.indices.cluster.IndicesClusterStateService.AllocatedIndices.IndexRemovalReason.DELETED; import static org.elasticsearch.indices.cluster.IndicesClusterStateService.AllocatedIndices.IndexRemovalReason.FAILURE; import static org.elasticsearch.indices.cluster.IndicesClusterStateService.AllocatedIndices.IndexRemovalReason.NO_LONGER_ASSIGNED; +import static org.elasticsearch.indices.cluster.IndicesClusterStateService.AllocatedIndices.IndexRemovalReason.REOPENED; public class IndicesClusterStateService extends AbstractLifecycleComponent implements ClusterStateApplier { private static final Logger logger = LogManager.getLogger(IndicesClusterStateService.class); @@ -240,7 +241,7 @@ public synchronized void applyClusterState(final ClusterChangedEvent event) { deleteIndices(event); // also deletes shards of deleted indices - removeUnallocatedIndices(event); // also removes shards of removed indices + removeIndices(event); // also removes shards of removed indices failMissingShards(state); @@ -352,17 +353,18 @@ protected void doRun() throws Exception { } /** - * Removes indices that have no shards allocated to this node. This does not delete the shard data as we wait for enough - * shard copies to exist in the cluster before deleting shard data (triggered by {@link org.elasticsearch.indices.store.IndicesStore}). + * Removes indices that have no shards allocated to this node or indices whose state has changed. This does not delete the shard data + * as we wait for enough shard copies to exist in the cluster before deleting shard data (triggered by + * {@link org.elasticsearch.indices.store.IndicesStore}). * * @param event the cluster changed event */ - private void removeUnallocatedIndices(final ClusterChangedEvent event) { + private void removeIndices(final ClusterChangedEvent event) { final ClusterState state = event.state(); final String localNodeId = state.nodes().getLocalNodeId(); assert localNodeId != null; - Set indicesWithShards = new HashSet<>(); + final Set indicesWithShards = new HashSet<>(); RoutingNode localRoutingNode = state.getRoutingNodes().node(localNodeId); if (localRoutingNode != null) { // null e.g. if we are not a data node for (ShardRouting shardRouting : localRoutingNode) { @@ -371,20 +373,27 @@ private void removeUnallocatedIndices(final ClusterChangedEvent event) { } for (AllocatedIndex indexService : indicesService) { - Index index = indexService.index(); - if (indicesWithShards.contains(index) == false) { + final Index index = indexService.index(); + final IndexMetaData indexMetaData = state.metaData().index(index); + final IndexMetaData existingMetaData = indexService.getIndexSettings().getIndexMetaData(); + + AllocatedIndices.IndexRemovalReason reason = null; + if (indexMetaData != null && indexMetaData.getState() != existingMetaData.getState()) { + reason = indexMetaData.getState() == IndexMetaData.State.CLOSE ? CLOSED : REOPENED; + } else if (indicesWithShards.contains(index) == false) { // if the cluster change indicates a brand new cluster, we only want // to remove the in-memory structures for the index and not delete the // contents on disk because the index will later be re-imported as a // dangling index - final IndexMetaData indexMetaData = state.metaData().index(index); assert indexMetaData != null || event.isNewCluster() : "index " + index + " does not exist in the cluster state, it should either " + "have been deleted or the cluster must be new"; - final AllocatedIndices.IndexRemovalReason reason = - indexMetaData != null && indexMetaData.getState() == IndexMetaData.State.CLOSE ? CLOSED : NO_LONGER_ASSIGNED; - logger.debug("{} removing index, [{}]", index, reason); - indicesService.removeIndex(index, reason, "removing index (no shards allocated)"); + reason = indexMetaData != null && indexMetaData.getState() == IndexMetaData.State.CLOSE ? CLOSED : NO_LONGER_ASSIGNED; + } + + if (reason != null) { + logger.debug("{} removing index ({})", index, reason); + indicesService.removeIndex(index, reason, "removing index (" + reason + ")"); } } } @@ -595,7 +604,7 @@ private void updateShard(DiscoveryNodes nodes, ShardRouting shardRouting, Shard ClusterState clusterState) { final ShardRouting currentRoutingEntry = shard.routingEntry(); assert currentRoutingEntry.isSameAllocation(shardRouting) : - "local shard has a different allocation id but wasn't cleaning by removeShards. " + "local shard has a different allocation id but wasn't cleaned by removeShards. " + "cluster state: " + shardRouting + " local: " + currentRoutingEntry; final long primaryTerm; @@ -730,7 +739,7 @@ private void failAndRemoveShard(ShardRouting shardRouting, boolean sendShardFail private void sendFailShard(ShardRouting shardRouting, String message, @Nullable Exception failure, ClusterState state) { try { logger.warn(() -> new ParameterizedMessage( - "[{}] marking and sending shard failed due to [{}]", shardRouting.shardId(), message), failure); + "{} marking and sending shard failed due to [{}]", shardRouting.shardId(), message), failure); failedShardsCache.put(shardRouting.shardId(), shardRouting); shardStateAction.localShardFailed(shardRouting, message, failure, SHARD_STATE_ACTION_LISTENER, state); } catch (Exception inner) { @@ -931,7 +940,7 @@ enum IndexRemovalReason { DELETED, /** - * The index have been closed. The index should be removed and all associated resources released. Persistent parts of the index + * The index has been closed. The index should be removed and all associated resources released. Persistent parts of the index * like the shards files, state and transaction logs are kept around in the case of a disaster recovery. */ CLOSED, @@ -941,7 +950,13 @@ enum IndexRemovalReason { * Persistent parts of the index like the shards files, state and transaction logs are kept around in the * case of a disaster recovery. */ - FAILURE + FAILURE, + + /** + * The index has been reopened. The index should be removed and all associated resources released. Persistent parts of the index + * like the shards files, state and transaction logs are kept around in the case of a disaster recovery. + */ + REOPENED, } } } diff --git a/server/src/main/java/org/elasticsearch/search/SearchService.java b/server/src/main/java/org/elasticsearch/search/SearchService.java index a14b4a328775c..b8bde4e4f5213 100644 --- a/server/src/main/java/org/elasticsearch/search/SearchService.java +++ b/server/src/main/java/org/elasticsearch/search/SearchService.java @@ -268,7 +268,7 @@ public void afterIndexRemoved(Index index, IndexSettings indexSettings, IndexRem // it's fine to keep the contexts open if the index is still "alive" // unfortunately we don't have a clear way to signal today why an index is closed. // to release memory and let references to the filesystem go etc. - if (reason == IndexRemovalReason.DELETED || reason == IndexRemovalReason.CLOSED) { + if (reason == IndexRemovalReason.DELETED || reason == IndexRemovalReason.CLOSED || reason == IndexRemovalReason.REOPENED) { freeAllContextForIndex(index); } diff --git a/server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataIndexStateServiceTests.java b/server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataIndexStateServiceTests.java index 56ee25ee5febb..4108c542d0cc5 100644 --- a/server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataIndexStateServiceTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataIndexStateServiceTests.java @@ -35,6 +35,7 @@ import org.elasticsearch.cluster.routing.RoutingTable; import org.elasticsearch.cluster.routing.ShardRouting; import org.elasticsearch.cluster.routing.ShardRoutingState; +import org.elasticsearch.cluster.routing.UnassignedInfo; import org.elasticsearch.cluster.shards.ClusterShardLimitIT; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.ValidationException; @@ -210,7 +211,14 @@ public void testAddIndexClosedBlocks() { for (Index index : indices) { assertTrue(blockedIndices.containsKey(index)); if (mixedVersions) { - assertIsClosed(index.getName(), updatedState); + assertThat(updatedState.metaData().index(index).getState(), is(IndexMetaData.State.CLOSE)); + assertTrue(updatedState.blocks().hasIndexBlock(index.getName(), MetaDataIndexStateService.INDEX_CLOSED_BLOCK)); + assertThat("Index " + index + " must have only 1 block with id=" + MetaDataIndexStateService.INDEX_CLOSED_BLOCK_ID, + updatedState.blocks().indices().getOrDefault(index.getName(), emptySet()).stream().filter(clusterBlock -> + clusterBlock.id() == MetaDataIndexStateService.INDEX_CLOSED_BLOCK_ID).count(), equalTo(1L)); + + final IndexRoutingTable indexRoutingTable = updatedState.routingTable().index(index); + assertThat(indexRoutingTable, nullValue()); } else { assertHasBlock(index.getName(), updatedState, blockedIndices.get(index)); } @@ -346,19 +354,18 @@ private static ClusterState addIndex(final ClusterState currentState, final ClusterState.Builder clusterStateBuilder = ClusterState.builder(currentState); clusterStateBuilder.metaData(MetaData.builder(currentState.metaData()).put(indexMetaData, true)); - if (state == IndexMetaData.State.OPEN) { - final IndexRoutingTable.Builder indexRoutingTable = IndexRoutingTable.builder(indexMetaData.getIndex()); - for (int j = 0; j < indexMetaData.getNumberOfShards(); j++) { - ShardId shardId = new ShardId(indexMetaData.getIndex(), j); - IndexShardRoutingTable.Builder indexShardRoutingBuilder = new IndexShardRoutingTable.Builder(shardId); - indexShardRoutingBuilder.addShard(newShardRouting(shardId, randomAlphaOfLength(10), true, ShardRoutingState.STARTED)); - for (int k = 0; k < indexMetaData.getNumberOfReplicas(); k++) { - indexShardRoutingBuilder.addShard(newShardRouting(shardId, randomAlphaOfLength(10), false, ShardRoutingState.STARTED)); - } - indexRoutingTable.addIndexShard(indexShardRoutingBuilder.build()); + final IndexRoutingTable.Builder indexRoutingTable = IndexRoutingTable.builder(indexMetaData.getIndex()); + for (int j = 0; j < indexMetaData.getNumberOfShards(); j++) { + ShardId shardId = new ShardId(indexMetaData.getIndex(), j); + IndexShardRoutingTable.Builder indexShardRoutingBuilder = new IndexShardRoutingTable.Builder(shardId); + indexShardRoutingBuilder.addShard(newShardRouting(shardId, randomAlphaOfLength(10), true, ShardRoutingState.STARTED)); + for (int k = 0; k < indexMetaData.getNumberOfReplicas(); k++) { + indexShardRoutingBuilder.addShard(newShardRouting(shardId, randomAlphaOfLength(10), false, ShardRoutingState.STARTED)); } - clusterStateBuilder.routingTable(RoutingTable.builder(currentState.routingTable()).add(indexRoutingTable).build()); + indexRoutingTable.addIndexShard(indexShardRoutingBuilder.build()); } + clusterStateBuilder.routingTable(RoutingTable.builder(currentState.routingTable()).add(indexRoutingTable).build()); + if (block != null) { clusterStateBuilder.blocks(ClusterBlocks.builder().blocks(currentState.blocks()).addIndexBlock(index, block)); } @@ -372,11 +379,19 @@ private static void assertIsOpened(final String indexName, final ClusterState cl private static void assertIsClosed(final String indexName, final ClusterState clusterState) { assertThat(clusterState.metaData().index(indexName).getState(), is(IndexMetaData.State.CLOSE)); - assertThat(clusterState.routingTable().index(indexName), nullValue()); assertThat(clusterState.blocks().hasIndexBlock(indexName, MetaDataIndexStateService.INDEX_CLOSED_BLOCK), is(true)); assertThat("Index " + indexName + " must have only 1 block with [id=" + MetaDataIndexStateService.INDEX_CLOSED_BLOCK_ID + "]", clusterState.blocks().indices().getOrDefault(indexName, emptySet()).stream() .filter(clusterBlock -> clusterBlock.id() == MetaDataIndexStateService.INDEX_CLOSED_BLOCK_ID).count(), equalTo(1L)); + + final IndexRoutingTable indexRoutingTable = clusterState.routingTable().index(indexName); + assertThat(indexRoutingTable, notNullValue()); + + for(IndexShardRoutingTable shardRoutingTable : indexRoutingTable) { + assertThat(shardRoutingTable.shards().stream().allMatch(ShardRouting::unassigned), is(true)); + assertThat(shardRoutingTable.shards().stream().map(ShardRouting::unassignedInfo).map(UnassignedInfo::getReason) + .allMatch(info -> info == UnassignedInfo.Reason.INDEX_CLOSED), is(true)); + } } private static void assertHasBlock(final String indexName, final ClusterState clusterState, final ClusterBlock closingBlock) { diff --git a/server/src/test/java/org/elasticsearch/cluster/routing/UnassignedInfoTests.java b/server/src/test/java/org/elasticsearch/cluster/routing/UnassignedInfoTests.java index 16cde1a990907..bc3191c14dfba 100644 --- a/server/src/test/java/org/elasticsearch/cluster/routing/UnassignedInfoTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/routing/UnassignedInfoTests.java @@ -40,6 +40,7 @@ import org.elasticsearch.index.Index; import org.elasticsearch.snapshots.Snapshot; import org.elasticsearch.snapshots.SnapshotId; +import org.elasticsearch.test.VersionUtils; import java.io.IOException; import java.nio.ByteBuffer; @@ -54,6 +55,7 @@ import static org.hamcrest.Matchers.nullValue; public class UnassignedInfoTests extends ESAllocationTestCase { + public void testReasonOrdinalOrder() { UnassignedInfo.Reason[] order = new UnassignedInfo.Reason[]{ UnassignedInfo.Reason.INDEX_CREATED, @@ -70,7 +72,8 @@ public void testReasonOrdinalOrder() { UnassignedInfo.Reason.REALLOCATED_REPLICA, UnassignedInfo.Reason.PRIMARY_FAILED, UnassignedInfo.Reason.FORCED_EMPTY_PRIMARY, - UnassignedInfo.Reason.MANUAL_ALLOCATION,}; + UnassignedInfo.Reason.MANUAL_ALLOCATION, + UnassignedInfo.Reason.INDEX_CLOSED,}; for (int i = 0; i < order.length; i++) { assertThat(order[i].ordinal(), equalTo(i)); } @@ -95,6 +98,21 @@ public void testSerialization() throws Exception { assertThat(read.getNumFailedAllocations(), equalTo(meta.getNumFailedAllocations())); } + public void testBwcSerialization() throws Exception { + final UnassignedInfo unassignedInfo = new UnassignedInfo(UnassignedInfo.Reason.INDEX_CLOSED, "message"); + BytesStreamOutput out = new BytesStreamOutput(); + out.setVersion(VersionUtils.randomVersionBetween(random(), Version.V_6_0_0, VersionUtils.getPreviousVersion(Version.V_7_0_0))); + unassignedInfo.writeTo(out); + out.close(); + + UnassignedInfo read = new UnassignedInfo(out.bytes().streamInput()); + assertThat(read.getReason(), equalTo(UnassignedInfo.Reason.REINITIALIZED)); + assertThat(read.getUnassignedTimeInMillis(), equalTo(unassignedInfo.getUnassignedTimeInMillis())); + assertThat(read.getMessage(), equalTo(unassignedInfo.getMessage())); + assertThat(read.getDetails(), equalTo(unassignedInfo.getDetails())); + assertThat(read.getNumFailedAllocations(), equalTo(unassignedInfo.getNumFailedAllocations())); + } + public void testIndexCreated() { MetaData metaData = MetaData.builder() .put(IndexMetaData.builder("test").settings(settings(Version.CURRENT)) diff --git a/server/src/test/java/org/elasticsearch/gateway/GatewayIndexStateIT.java b/server/src/test/java/org/elasticsearch/gateway/GatewayIndexStateIT.java index ebdae985a39c7..541a24247473a 100644 --- a/server/src/test/java/org/elasticsearch/gateway/GatewayIndexStateIT.java +++ b/server/src/test/java/org/elasticsearch/gateway/GatewayIndexStateIT.java @@ -54,9 +54,11 @@ import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; @ClusterScope(scope = Scope.TEST, numDataNodes = 0) @@ -113,11 +115,11 @@ public void testSimpleOpenClose() throws Exception { client().prepareIndex("test", "type1", "1").setSource("field1", "value1").get(); logger.info("--> closing test index..."); - client().admin().indices().prepareClose("test").get(); + assertAcked(client().admin().indices().prepareClose("test")); stateResponse = client().admin().cluster().prepareState().execute().actionGet(); assertThat(stateResponse.getState().metaData().index("test").getState(), equalTo(IndexMetaData.State.CLOSE)); - assertThat(stateResponse.getState().routingTable().index("test"), nullValue()); + assertThat(stateResponse.getState().routingTable().index("test"), notNullValue()); logger.info("--> verifying that the state is green"); ensureGreen(); @@ -136,7 +138,7 @@ public void testSimpleOpenClose() throws Exception { ensureGreen(); logger.info("--> opening the first index again..."); - client().admin().indices().prepareOpen("test").execute().actionGet(); + assertAcked(client().admin().indices().prepareOpen("test")); logger.info("--> verifying that the state is green"); ensureGreen(); @@ -152,10 +154,10 @@ public void testSimpleOpenClose() throws Exception { assertThat(getResponse.isExists(), equalTo(true)); logger.info("--> closing test index..."); - client().admin().indices().prepareClose("test").execute().actionGet(); + assertAcked(client().admin().indices().prepareClose("test")); stateResponse = client().admin().cluster().prepareState().execute().actionGet(); assertThat(stateResponse.getState().metaData().index("test").getState(), equalTo(IndexMetaData.State.CLOSE)); - assertThat(stateResponse.getState().routingTable().index("test"), nullValue()); + assertThat(stateResponse.getState().routingTable().index("test"), notNullValue()); logger.info("--> restarting nodes..."); internalCluster().fullRestart(); @@ -252,11 +254,11 @@ public void testTwoNodesSingleDoc() throws Exception { } logger.info("--> closing test index..."); - client().admin().indices().prepareClose("test").execute().actionGet(); + assertAcked(client().admin().indices().prepareClose("test")); ClusterStateResponse stateResponse = client().admin().cluster().prepareState().execute().actionGet(); assertThat(stateResponse.getState().metaData().index("test").getState(), equalTo(IndexMetaData.State.CLOSE)); - assertThat(stateResponse.getState().routingTable().index("test"), nullValue()); + assertThat(stateResponse.getState().routingTable().index("test"), notNullValue()); logger.info("--> opening the index..."); client().admin().indices().prepareOpen("test").execute().actionGet(); diff --git a/server/src/test/java/org/elasticsearch/index/shard/IndexShardIT.java b/server/src/test/java/org/elasticsearch/index/shard/IndexShardIT.java index 250af071cf6fe..71b5da28274aa 100644 --- a/server/src/test/java/org/elasticsearch/index/shard/IndexShardIT.java +++ b/server/src/test/java/org/elasticsearch/index/shard/IndexShardIT.java @@ -276,6 +276,8 @@ public void testExpectedShardSizeIsPresent() throws InterruptedException { assertTrue(test > 0); } + // NORELEASE This test need to be adapted for replicated closed indices + @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/33888") public void testIndexCanChangeCustomDataPath() throws Exception { Environment env = getInstanceFromNode(Environment.class); Path idxPath = env.sharedDataFile().resolve(randomAlphaOfLength(10)); @@ -922,27 +924,17 @@ public void testNoOpEngineFactoryTakesPrecedence() throws IOException { createIndex(indexName, Settings.builder().put("index.number_of_shards", 1).put("index.number_of_replicas", 0).build()); ensureGreen(); - client().admin().indices().prepareClose(indexName).get(); + assertAcked(client().admin().indices().prepareClose(indexName)); final ClusterService clusterService = getInstanceFromNode(ClusterService.class); final ClusterState clusterState = clusterService.state(); - IndexMetaData indexMetaData = clusterState.metaData().index(indexName); + final IndexMetaData indexMetaData = clusterState.metaData().index(indexName); final IndicesService indicesService = getInstanceFromNode(IndicesService.class); - - final ShardId shardId = new ShardId(indexMetaData.getIndex(), 0); - final DiscoveryNode node = clusterService.localNode(); - final ShardRouting routing = - newShardRouting(shardId, node.getId(), true, ShardRoutingState.INITIALIZING, RecoverySource.EmptyStoreRecoverySource.INSTANCE); - final IndexService indexService = indicesService.createIndex(indexMetaData, Collections.emptyList()); - try { - final IndexShard indexShard = indexService.createShard(routing, id -> {}, (s, leases, listener) -> {}); - indexShard.markAsRecovering("store", new RecoveryState(indexShard.routingEntry(), node, null)); - indexShard.recoverFromStore(); + + for (IndexShard indexShard : indexService) { assertThat(indexShard.getEngine(), instanceOf(NoOpEngine.class)); - } finally { - indexService.close("test terminated", true); } } } diff --git a/server/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java b/server/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java index 1aa042edacd67..8ee47f50a7417 100644 --- a/server/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java +++ b/server/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java @@ -271,6 +271,8 @@ public void testDeleteIndexStore() throws Exception { ensureGreen("test"); } + // NORELEASE This test need to be adapted for replicated closed indices + @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/33888") public void testPendingTasks() throws Exception { IndicesService indicesService = getIndicesService(); IndexService test = createIndex("test"); diff --git a/server/src/test/java/org/elasticsearch/indices/state/CloseIndexIT.java b/server/src/test/java/org/elasticsearch/indices/state/CloseIndexIT.java index 1d32283c6cb94..ca3f6e694097d 100644 --- a/server/src/test/java/org/elasticsearch/indices/state/CloseIndexIT.java +++ b/server/src/test/java/org/elasticsearch/indices/state/CloseIndexIT.java @@ -49,7 +49,6 @@ import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; public class CloseIndexIT extends ESIntegTestCase { @@ -310,7 +309,7 @@ static void assertIndexIsClosed(final String... indices) { final ClusterState clusterState = client().admin().cluster().prepareState().get().getState(); for (String index : indices) { assertThat(clusterState.metaData().indices().get(index).getState(), is(IndexMetaData.State.CLOSE)); - assertThat(clusterState.routingTable().index(index), nullValue()); + assertThat(clusterState.routingTable().index(index), notNullValue()); assertThat(clusterState.blocks().hasIndexBlock(index, MetaDataIndexStateService.INDEX_CLOSED_BLOCK), is(true)); assertThat("Index " + index + " must have only 1 block with [id=" + MetaDataIndexStateService.INDEX_CLOSED_BLOCK_ID + "]", clusterState.blocks().indices().getOrDefault(index, emptySet()).stream() diff --git a/server/src/test/java/org/elasticsearch/indices/state/SimpleIndexStateIT.java b/server/src/test/java/org/elasticsearch/indices/state/SimpleIndexStateIT.java index 1cc2d3e68e2ae..050d77a223101 100644 --- a/server/src/test/java/org/elasticsearch/indices/state/SimpleIndexStateIT.java +++ b/server/src/test/java/org/elasticsearch/indices/state/SimpleIndexStateIT.java @@ -36,7 +36,7 @@ import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.notNullValue; @ESIntegTestCase.ClusterScope(minNumDataNodes = 2) public class SimpleIndexStateIT extends ESIntegTestCase { @@ -65,7 +65,7 @@ public void testSimpleOpenClose() { stateResponse = client().admin().cluster().prepareState().get(); assertThat(stateResponse.getState().metaData().index("test").getState(), equalTo(IndexMetaData.State.CLOSE)); - assertThat(stateResponse.getState().routingTable().index("test"), nullValue()); + assertThat(stateResponse.getState().routingTable().index("test"), notNullValue()); logger.info("--> trying to index into a closed index ..."); try { diff --git a/server/src/test/java/org/elasticsearch/search/scroll/SearchScrollIT.java b/server/src/test/java/org/elasticsearch/search/scroll/SearchScrollIT.java index 9fb05af2040b3..e0ae78dff3466 100644 --- a/server/src/test/java/org/elasticsearch/search/scroll/SearchScrollIT.java +++ b/server/src/test/java/org/elasticsearch/search/scroll/SearchScrollIT.java @@ -521,11 +521,10 @@ public void testStringSortMissingAscTerminates() throws Exception { assertThat(response.getHits().getHits().length, equalTo(0)); } - public void testCloseAndReopenOrDeleteWithActiveScroll() throws IOException { + public void testCloseAndReopenOrDeleteWithActiveScroll() { createIndex("test"); for (int i = 0; i < 100; i++) { - client().prepareIndex("test", "type1", Integer.toString(i)).setSource(jsonBuilder().startObject().field("field", i).endObject()) - .get(); + client().prepareIndex("test", "type1", Integer.toString(i)).setSource("field", i).get(); } refresh(); SearchResponse searchResponse = client().prepareSearch() @@ -541,11 +540,11 @@ public void testCloseAndReopenOrDeleteWithActiveScroll() throws IOException { assertThat(((Number) hit.getSortValues()[0]).longValue(), equalTo(counter++)); } if (randomBoolean()) { - client().admin().indices().prepareClose("test").get(); - client().admin().indices().prepareOpen("test").get(); + assertAcked(client().admin().indices().prepareClose("test")); + assertAcked(client().admin().indices().prepareOpen("test")); ensureGreen("test"); } else { - client().admin().indices().prepareDelete("test").get(); + assertAcked(client().admin().indices().prepareDelete("test")); } } diff --git a/server/src/test/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java b/server/src/test/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java index 78892516c4ade..68def650b6d4b 100644 --- a/server/src/test/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java +++ b/server/src/test/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java @@ -1550,7 +1550,7 @@ public void testSnapshotClosedIndex() throws Exception { assertAcked(client.admin().indices().prepareClose("test-idx-closed")); ClusterStateResponse stateResponse = client.admin().cluster().prepareState().get(); assertThat(stateResponse.getState().metaData().index("test-idx-closed").getState(), equalTo(IndexMetaData.State.CLOSE)); - assertThat(stateResponse.getState().routingTable().index("test-idx-closed"), nullValue()); + assertThat(stateResponse.getState().routingTable().index("test-idx-closed"), notNullValue()); logger.info("--> snapshot"); CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap") @@ -3749,7 +3749,7 @@ public void testRestoreIncreasesPrimaryTerms() { final IndexMetaData restoredIndexMetaData = client().admin().cluster().prepareState().clear().setIndices(indexName) .setMetaData(true).get().getState().metaData().index(indexName); for (int shardId = 0; shardId < numPrimaries; shardId++) { - assertThat(restoredIndexMetaData.primaryTerm(shardId), equalTo(primaryTerms.get(shardId) + 1)); + assertThat(restoredIndexMetaData.primaryTerm(shardId), greaterThan(primaryTerms.get(shardId))); } }