diff --git a/server/src/internalClusterTest/java/org/elasticsearch/indices/state/CloseIndexIT.java b/server/src/internalClusterTest/java/org/elasticsearch/indices/state/CloseIndexIT.java index f20c7162e4715..4a8415d32ed82 100644 --- a/server/src/internalClusterTest/java/org/elasticsearch/indices/state/CloseIndexIT.java +++ b/server/src/internalClusterTest/java/org/elasticsearch/indices/state/CloseIndexIT.java @@ -166,16 +166,39 @@ public void testCloseAlreadyClosedIndex() throws Exception { public void testCloseUnassignedIndex() throws Exception { final String indexName = randomAlphaOfLength(10).toLowerCase(Locale.ROOT); assertAcked( - prepareCreate(indexName).setWaitForActiveShards(ActiveShardCount.NONE) - .setSettings(Settings.builder().put("index.routing.allocation.include._name", "nothing").build()) + prepareCreate(indexName).setSettings(Settings.builder().put(IndexSettings.INDEX_REFRESH_INTERVAL_SETTING.getKey(), "1m") + .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0).build()) ); - final ClusterState clusterState = clusterAdmin().prepareState().get().getState(); - assertThat(clusterState.metadata().indices().get(indexName).getState(), is(IndexMetadata.State.OPEN)); - assertThat(clusterState.routingTable().allShards().allMatch(ShardRouting::unassigned), is(true)); + final int nbDocs = randomIntBetween(1, 1); + indexRandom( + randomBoolean(), + false, + randomBoolean(), + IntStream.range(0, nbDocs) + .mapToObj(i -> client().prepareIndex(indexName).setId(String.valueOf(i)).setSource("num", i)) + .collect(toList()) + ); - assertBusy(() -> closeIndices(indicesAdmin().prepareClose(indexName).setWaitForActiveShards(ActiveShardCount.NONE))); + internalCluster().restartNode(internalCluster().nodesInclude(indexName).iterator().next(), new InternalTestCluster.RestartCallback() { + @Override + public Settings onNodeStopped(String nodeName) throws Exception { + closeIndices(indicesAdmin().prepareClose(indexName).setWaitForActiveShards(ActiveShardCount.NONE)); + + return super.onNodeStopped(nodeName); + } + }); assertIndexIsClosed(indexName); + + + String newNode = internalCluster().startDataOnlyNode(); +// assertAcked(client().admin().indices().prepareUpdateSettings(indexName).setSettings(Settings.builder().put("index.routing.allocation.include._name", newNode))); +// waitForRelocation(); + + assertAcked(client().admin().indices().prepareOpen(indexName)); + + assertHitCount(client().prepareSearch(indexName).setSize(0).get(), nbDocs); + } public void testConcurrentClose() throws InterruptedException { diff --git a/server/src/internalClusterTest/java/org/elasticsearch/indices/state/UnsafeCloseIndexIT.java b/server/src/internalClusterTest/java/org/elasticsearch/indices/state/UnsafeCloseIndexIT.java new file mode 100644 index 0000000000000..922737039c7d7 --- /dev/null +++ b/server/src/internalClusterTest/java/org/elasticsearch/indices/state/UnsafeCloseIndexIT.java @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.indices.state; + +import org.elasticsearch.action.support.ActiveShardCount; +import org.elasticsearch.cluster.metadata.IndexMetadata; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.IndexSettings; +import org.elasticsearch.test.ESIntegTestCase; +import org.elasticsearch.test.InternalTestCluster; + +import java.util.Locale; +import java.util.stream.IntStream; + +import static java.util.stream.Collectors.toList; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; + +@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, numClientNodes = 0) +public class UnsafeCloseIndexIT extends ESIntegTestCase { + public void testCloseUnassignedIndex() throws Exception { + internalCluster().startMasterOnlyNode(); + internalCluster().startDataOnlyNode(); + final String indexName = randomAlphaOfLength(10).toLowerCase(Locale.ROOT); + assertAcked( + prepareCreate(indexName).setSettings(Settings.builder().put(IndexSettings.INDEX_REFRESH_INTERVAL_SETTING.getKey(), "1m") + .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0).build()) + ); + + final int nbDocs = randomIntBetween(1, 1); + indexRandom( + randomBoolean(), + false, + randomBoolean(), + IntStream.range(0, nbDocs) + .mapToObj(i -> client().prepareIndex(indexName).setId(String.valueOf(i)).setSource("num", i)) + .collect(toList()) + ); + + internalCluster().restartNode(internalCluster().nodesInclude(indexName).iterator().next(), new InternalTestCluster.RestartCallback() { + @Override + public Settings onNodeStopped(String nodeName) throws Exception { + assertAcked(indicesAdmin().prepareClose(indexName).setWaitForActiveShards(ActiveShardCount.NONE)); + + return super.onNodeStopped(nodeName); + } + }); + CloseIndexIT.assertIndexIsClosed(indexName); + + + String newNode = internalCluster().startDataOnlyNode(); + assertAcked(client().admin().indices().prepareUpdateSettings(indexName).setSettings(Settings.builder().put("index.routing.allocation.include._name", newNode))); + waitForRelocation(); + + assertAcked(client().admin().indices().prepareOpen(indexName)); + + assertHitCount(client().prepareSearch(indexName).setSize(0).get(), nbDocs); + + } + +} diff --git a/server/src/main/java/org/elasticsearch/index/engine/Engine.java b/server/src/main/java/org/elasticsearch/index/engine/Engine.java index 7f896c352d958..722c52b5ae177 100644 --- a/server/src/main/java/org/elasticsearch/index/engine/Engine.java +++ b/server/src/main/java/org/elasticsearch/index/engine/Engine.java @@ -1871,7 +1871,7 @@ public void flushAndClose() throws IOException { // TODO we might force a flush in the future since we have the write lock already even though recoveries // are running. // TODO: We are not waiting for full durability here atm because we are on the cluster state update thread - flush(false, false, ActionListener.noop()); +// flush(false, false, ActionListener.noop()); } catch (AlreadyClosedException ex) { logger.debug("engine already closed - skipping flushAndClose"); } diff --git a/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java b/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java index ba8fd01ae028e..830dffda46098 100644 --- a/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java +++ b/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java @@ -2800,7 +2800,7 @@ public void maybeSyncGlobalCheckpoint(final String reason) { || trackedGlobalCheckpointsNeedSync; // only sync if index is not closed and there is a shard lagging the primary if (syncNeeded && indexSettings.getIndexMetadata().getState() == IndexMetadata.State.OPEN) { - syncGlobalCheckpoints(reason); +// syncGlobalCheckpoints(reason); } } } diff --git a/server/src/main/java/org/elasticsearch/index/translog/Translog.java b/server/src/main/java/org/elasticsearch/index/translog/Translog.java index 38f44f453bedc..4322266e9d901 100644 --- a/server/src/main/java/org/elasticsearch/index/translog/Translog.java +++ b/server/src/main/java/org/elasticsearch/index/translog/Translog.java @@ -387,7 +387,7 @@ assert calledFromOutsideOrViaTragedyClose() if (closed.compareAndSet(false, true)) { try (ReleasableLock lock = writeLock.acquire()) { try { - current.sync(); +// current.sync(); } finally { closeFilesIfNoPendingRetentionLocks(); }