diff --git a/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/MetadataIndexStateServiceIT.java b/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/MetadataIndexStateServiceIT.java new file mode 100644 index 0000000000000..026ee43454c07 --- /dev/null +++ b/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/MetadataIndexStateServiceIT.java @@ -0,0 +1,128 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.cluster.metadata; + +import org.opensearch.action.admin.cluster.state.ClusterStateResponse; +import org.opensearch.action.admin.indices.open.OpenIndexResponse; +import org.opensearch.action.admin.indices.settings.get.GetSettingsResponse; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.action.support.WriteRequest; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.FeatureFlags; +import org.opensearch.remotestore.RemoteStoreBaseIntegTestCase; +import org.opensearch.test.OpenSearchIntegTestCase; + +import java.util.concurrent.TimeUnit; + +import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_REPLICAS; +import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_SEARCH_REPLICAS; +import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_SHARDS; +import static org.opensearch.test.hamcrest.OpenSearchAssertions.assertAcked; +import static org.opensearch.test.hamcrest.OpenSearchAssertions.assertHitCount; + +@OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.TEST, numDataNodes = 0) +public class MetadataIndexStateServiceIT extends RemoteStoreBaseIntegTestCase { + + private static final String TEST_INDEX = "test_open_close_index"; + + @Override + protected Settings featureFlagSettings() { + return Settings.builder().put(super.featureFlagSettings()).put(FeatureFlags.READER_WRITER_SPLIT_EXPERIMENTAL, Boolean.TRUE).build(); + } + + public void testIndexCloseAndOpen() throws Exception { + internalCluster().startClusterManagerOnlyNode(); + internalCluster().startDataOnlyNodes(2); + + Settings specificSettings = Settings.builder().put(SETTING_NUMBER_OF_SHARDS, 1).put(SETTING_NUMBER_OF_REPLICAS, 1).build(); + + createIndex(TEST_INDEX, specificSettings); + ensureGreen(TEST_INDEX); + + for (int i = 0; i < 10; i++) { + client().prepareIndex(TEST_INDEX) + .setId(Integer.toString(i)) + .setSource("field1", "value" + i) + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .get(); + } + + assertAcked(client().admin().indices().prepareClose(TEST_INDEX).get()); + + ClusterStateResponse clusterStateResponse = client().admin().cluster().prepareState().get(); + IndexMetadata indexMetadata = clusterStateResponse.getState().metadata().index(TEST_INDEX); + assertEquals(IndexMetadata.State.CLOSE, indexMetadata.getState()); + + OpenIndexResponse openIndexResponse = client().admin().indices().prepareOpen(TEST_INDEX).get(); + + assertTrue("Open operation should be acknowledged", openIndexResponse.isAcknowledged()); + assertTrue("Open operation shards should be acknowledged", openIndexResponse.isShardsAcknowledged()); + + clusterStateResponse = client().admin().cluster().prepareState().get(); + indexMetadata = clusterStateResponse.getState().metadata().index(TEST_INDEX); + assertEquals(IndexMetadata.State.OPEN, indexMetadata.getState()); + + assertBusy(() -> { + SearchResponse searchResponse = client().prepareSearch(TEST_INDEX).get(); + assertHitCount(searchResponse, 10); + }, 30, TimeUnit.SECONDS); + } + + public void testIndexCloseAndOpenWithSearchOnlyMode() throws Exception { + internalCluster().startClusterManagerOnlyNode(); + internalCluster().startDataOnlyNodes(2); + internalCluster().startSearchOnlyNodes(1); + + Settings specificSettings = Settings.builder() + .put(SETTING_NUMBER_OF_SHARDS, 1) + .put(SETTING_NUMBER_OF_REPLICAS, 1) + .put(SETTING_NUMBER_OF_SEARCH_REPLICAS, 1) + .build(); + + createIndex(TEST_INDEX, specificSettings); + ensureGreen(TEST_INDEX); + + for (int i = 0; i < 10; i++) { + client().prepareIndex(TEST_INDEX) + .setId(Integer.toString(i)) + .setSource("field1", "value" + i) + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .get(); + } + + assertAcked(client().admin().indices().prepareScaleSearchOnly(TEST_INDEX, true).get()); + ensureGreen(TEST_INDEX); + + GetSettingsResponse settingsResponse = client().admin().indices().prepareGetSettings(TEST_INDEX).get(); + assertTrue(settingsResponse.getSetting(TEST_INDEX, IndexMetadata.INDEX_BLOCKS_SEARCH_ONLY_SETTING.getKey()).equals("true")); + + assertAcked(client().admin().indices().prepareClose(TEST_INDEX).get()); + + ClusterStateResponse clusterStateResponse = client().admin().cluster().prepareState().get(); + IndexMetadata indexMetadata = clusterStateResponse.getState().metadata().index(TEST_INDEX); + assertEquals(IndexMetadata.State.CLOSE, indexMetadata.getState()); + + OpenIndexResponse openIndexResponse = client().admin().indices().prepareOpen(TEST_INDEX).get(); + + assertTrue("Open operation should be acknowledged", openIndexResponse.isAcknowledged()); + assertTrue("Open operation shards should be acknowledged", openIndexResponse.isShardsAcknowledged()); + + clusterStateResponse = client().admin().cluster().prepareState().get(); + indexMetadata = clusterStateResponse.getState().metadata().index(TEST_INDEX); + assertEquals(IndexMetadata.State.OPEN, indexMetadata.getState()); + + settingsResponse = client().admin().indices().prepareGetSettings(TEST_INDEX).get(); + assertTrue(settingsResponse.getSetting(TEST_INDEX, IndexMetadata.INDEX_BLOCKS_SEARCH_ONLY_SETTING.getKey()).equals("true")); + + assertBusy(() -> { + SearchResponse searchResponse = client().prepareSearch(TEST_INDEX).get(); + assertHitCount(searchResponse, 10); + }, 30, TimeUnit.SECONDS); + } +} diff --git a/server/src/main/java/org/opensearch/action/support/ActiveShardCount.java b/server/src/main/java/org/opensearch/action/support/ActiveShardCount.java index e91342a7ce4b8..ad4d99929cbfd 100644 --- a/server/src/main/java/org/opensearch/action/support/ActiveShardCount.java +++ b/server/src/main/java/org/opensearch/action/support/ActiveShardCount.java @@ -178,9 +178,12 @@ public boolean enoughShardsActive(final ClusterState clusterState, final String. continue; } assert indexRoutingTable != null; + if (indexRoutingTable.allPrimaryShardsActive() == false) { - // all primary shards aren't active yet - return false; + if (indexMetadata.getSettings().getAsBoolean(IndexMetadata.INDEX_BLOCKS_SEARCH_ONLY_SETTING.getKey(), false) == false) { + // all primary shards aren't active yet + return false; + } } ActiveShardCount waitForActiveShards = this; if (waitForActiveShards == ActiveShardCount.DEFAULT) { diff --git a/server/src/main/java/org/opensearch/cluster/metadata/MetadataIndexStateService.java b/server/src/main/java/org/opensearch/cluster/metadata/MetadataIndexStateService.java index f0a74653f22ce..5edee81ad0ec5 100644 --- a/server/src/main/java/org/opensearch/cluster/metadata/MetadataIndexStateService.java +++ b/server/src/main/java/org/opensearch/cluster/metadata/MetadataIndexStateService.java @@ -675,7 +675,7 @@ private void sendVerifyShardBeforeCloseRequest( final ActionListener listener ) { final ShardId shardId = shardRoutingTable.shardId(); - if (shardRoutingTable.primaryShard().unassigned()) { + if (shardRoutingTable.primaryShard() == null || shardRoutingTable.primaryShard().unassigned()) { logger.debug("primary shard {} is unassigned, ignoring", shardId); final ReplicationResponse response = new ReplicationResponse(); response.setShardInfo(new ReplicationResponse.ShardInfo(shardRoutingTable.size(), shardRoutingTable.size())); diff --git a/server/src/main/java/org/opensearch/cluster/routing/IndexRoutingTable.java b/server/src/main/java/org/opensearch/cluster/routing/IndexRoutingTable.java index d1bb689672cca..971c8ef95282e 100644 --- a/server/src/main/java/org/opensearch/cluster/routing/IndexRoutingTable.java +++ b/server/src/main/java/org/opensearch/cluster/routing/IndexRoutingTable.java @@ -275,7 +275,7 @@ public boolean allPrimaryShardsActive() { public int primaryShardsActive() { int counter = 0; for (IndexShardRoutingTable shardRoutingTable : this) { - if (shardRoutingTable.primaryShard().active()) { + if (shardRoutingTable.primaryShard() != null && shardRoutingTable.primaryShard().active()) { counter++; } }