|
32 | 32 |
|
33 | 33 | package org.opensearch.gateway;
|
34 | 34 |
|
| 35 | +import org.opensearch.Version; |
35 | 36 | import org.opensearch.action.admin.cluster.configuration.AddVotingConfigExclusionsAction;
|
36 | 37 | import org.opensearch.action.admin.cluster.configuration.AddVotingConfigExclusionsRequest;
|
37 | 38 | import org.opensearch.action.admin.cluster.configuration.ClearVotingConfigExclusionsAction;
|
38 | 39 | import org.opensearch.action.admin.cluster.configuration.ClearVotingConfigExclusionsRequest;
|
| 40 | +import org.opensearch.action.admin.cluster.reroute.ClusterRerouteResponse; |
39 | 41 | import org.opensearch.action.admin.cluster.shards.ClusterSearchShardsGroup;
|
40 | 42 | import org.opensearch.action.admin.cluster.shards.ClusterSearchShardsResponse;
|
41 | 43 | import org.opensearch.action.admin.indices.recovery.RecoveryResponse;
|
|
46 | 48 | import org.opensearch.cluster.coordination.ElectionSchedulerFactory;
|
47 | 49 | import org.opensearch.cluster.metadata.IndexMetadata;
|
48 | 50 | import org.opensearch.cluster.node.DiscoveryNode;
|
| 51 | +import org.opensearch.cluster.routing.ShardRouting; |
49 | 52 | import org.opensearch.cluster.routing.UnassignedInfo;
|
50 | 53 | import org.opensearch.cluster.service.ClusterService;
|
51 | 54 | import org.opensearch.common.settings.Settings;
|
|
63 | 66 | import org.opensearch.indices.recovery.RecoveryState;
|
64 | 67 | import org.opensearch.indices.replication.common.ReplicationLuceneIndex;
|
65 | 68 | import org.opensearch.indices.store.ShardAttributes;
|
| 69 | +import org.opensearch.indices.store.TransportNodesListShardStoreMetadataBatch; |
| 70 | +import org.opensearch.indices.store.TransportNodesListShardStoreMetadataHelper; |
66 | 71 | import org.opensearch.plugins.Plugin;
|
67 | 72 | import org.opensearch.test.InternalSettingsPlugin;
|
68 | 73 | import org.opensearch.test.InternalTestCluster.RestartCallback;
|
|
82 | 87 | import java.util.List;
|
83 | 88 | import java.util.Map;
|
84 | 89 | import java.util.Set;
|
| 90 | +import java.util.concurrent.ExecutionException; |
85 | 91 | import java.util.stream.IntStream;
|
86 | 92 |
|
| 93 | +import static java.util.Collections.emptyMap; |
| 94 | +import static java.util.Collections.emptySet; |
87 | 95 | import static org.opensearch.cluster.coordination.ClusterBootstrapService.INITIAL_CLUSTER_MANAGER_NODES_SETTING;
|
88 | 96 | import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_REPLICAS;
|
89 | 97 | import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_SHARDS;
|
@@ -817,6 +825,131 @@ public void testShardFetchCorruptedShardsUsingBatchAction() throws Exception {
|
817 | 825 | assertTrue(nodeGatewayStartedShards.primary());
|
818 | 826 | }
|
819 | 827 |
|
| 828 | + public void testSingleShardStoreFetchUsingBatchAction() throws ExecutionException, InterruptedException { |
| 829 | + String indexName = "test"; |
| 830 | + DiscoveryNode[] nodes = getDiscoveryNodes(); |
| 831 | + TransportNodesListShardStoreMetadataBatch.NodesStoreFilesMetadataBatch response = prepareAndSendRequest( |
| 832 | + new String[] { indexName }, |
| 833 | + nodes |
| 834 | + ); |
| 835 | + Index index = resolveIndex(indexName); |
| 836 | + ShardId shardId = new ShardId(index, 0); |
| 837 | + TransportNodesListShardStoreMetadataBatch.NodeStoreFilesMetadata nodeStoreFilesMetadata = response.getNodesMap() |
| 838 | + .get(nodes[0].getId()) |
| 839 | + .getNodeStoreFilesMetadataBatch() |
| 840 | + .get(shardId); |
| 841 | + assertNodeStoreFilesMetadataSuccessCase(nodeStoreFilesMetadata, shardId); |
| 842 | + } |
| 843 | + |
| 844 | + public void testShardStoreFetchMultiNodeMultiIndexesUsingBatchAction() throws Exception { |
| 845 | + internalCluster().startNodes(2); |
| 846 | + String indexName1 = "test1"; |
| 847 | + String indexName2 = "test2"; |
| 848 | + DiscoveryNode[] nodes = getDiscoveryNodes(); |
| 849 | + TransportNodesListShardStoreMetadataBatch.NodesStoreFilesMetadataBatch response = prepareAndSendRequest( |
| 850 | + new String[] { indexName1, indexName2 }, |
| 851 | + nodes |
| 852 | + ); |
| 853 | + ClusterSearchShardsResponse searchShardsResponse = client().admin().cluster().prepareSearchShards(indexName1, indexName2).get(); |
| 854 | + for (ClusterSearchShardsGroup clusterSearchShardsGroup : searchShardsResponse.getGroups()) { |
| 855 | + ShardId shardId = clusterSearchShardsGroup.getShardId(); |
| 856 | + ShardRouting[] shardRoutings = clusterSearchShardsGroup.getShards(); |
| 857 | + assertEquals(2, shardRoutings.length); |
| 858 | + for (ShardRouting shardRouting : shardRoutings) { |
| 859 | + TransportNodesListShardStoreMetadataBatch.NodeStoreFilesMetadata nodeStoreFilesMetadata = response.getNodesMap() |
| 860 | + .get(shardRouting.currentNodeId()) |
| 861 | + .getNodeStoreFilesMetadataBatch() |
| 862 | + .get(shardId); |
| 863 | + assertNodeStoreFilesMetadataSuccessCase(nodeStoreFilesMetadata, shardId); |
| 864 | + } |
| 865 | + } |
| 866 | + } |
| 867 | + |
| 868 | + public void testShardStoreFetchNodeNotConnectedUsingBatchAction() { |
| 869 | + DiscoveryNode nonExistingNode = new DiscoveryNode("foo", buildNewFakeTransportAddress(), emptyMap(), emptySet(), Version.CURRENT); |
| 870 | + String indexName = "test"; |
| 871 | + TransportNodesListShardStoreMetadataBatch.NodesStoreFilesMetadataBatch response = prepareAndSendRequest( |
| 872 | + new String[] { indexName }, |
| 873 | + new DiscoveryNode[] { nonExistingNode } |
| 874 | + ); |
| 875 | + assertTrue(response.hasFailures()); |
| 876 | + assertEquals(1, response.failures().size()); |
| 877 | + assertEquals(nonExistingNode.getId(), response.failures().get(0).nodeId()); |
| 878 | + } |
| 879 | + |
| 880 | + public void testShardStoreFetchCorruptedIndexUsingBatchAction() throws Exception { |
| 881 | + internalCluster().startNodes(2); |
| 882 | + String index1Name = "test1"; |
| 883 | + String index2Name = "test2"; |
| 884 | + prepareIndices(new String[] { index1Name, index2Name }, 1, 1); |
| 885 | + Map<ShardId, ShardAttributes> shardAttributesMap = prepareRequestMap(new String[] { index1Name, index2Name }, 1); |
| 886 | + Index index1 = resolveIndex(index1Name); |
| 887 | + ShardId shardId1 = new ShardId(index1, 0); |
| 888 | + ClusterSearchShardsResponse searchShardsResponse = client().admin().cluster().prepareSearchShards(index1Name).get(); |
| 889 | + assertEquals(2, searchShardsResponse.getNodes().length); |
| 890 | + |
| 891 | + // corrupt test1 index shards |
| 892 | + corruptShard(searchShardsResponse.getNodes()[0].getName(), shardId1); |
| 893 | + corruptShard(searchShardsResponse.getNodes()[1].getName(), shardId1); |
| 894 | + ClusterRerouteResponse clusterRerouteResponse = client().admin().cluster().prepareReroute().setRetryFailed(false).get(); |
| 895 | + DiscoveryNode[] discoveryNodes = getDiscoveryNodes(); |
| 896 | + TransportNodesListShardStoreMetadataBatch.NodesStoreFilesMetadataBatch response; |
| 897 | + response = ActionTestUtils.executeBlocking( |
| 898 | + internalCluster().getInstance(TransportNodesListShardStoreMetadataBatch.class), |
| 899 | + new TransportNodesListShardStoreMetadataBatch.Request(shardAttributesMap, discoveryNodes) |
| 900 | + ); |
| 901 | + Map<ShardId, TransportNodesListShardStoreMetadataBatch.NodeStoreFilesMetadata> nodeStoreFilesMetadata = response.getNodesMap() |
| 902 | + .get(discoveryNodes[0].getId()) |
| 903 | + .getNodeStoreFilesMetadataBatch(); |
| 904 | + // We don't store exception in case of corrupt index, rather just return an empty response |
| 905 | + assertNull(nodeStoreFilesMetadata.get(shardId1).getStoreFileFetchException()); |
| 906 | + assertEquals(shardId1, nodeStoreFilesMetadata.get(shardId1).storeFilesMetadata().shardId()); |
| 907 | + assertTrue(nodeStoreFilesMetadata.get(shardId1).storeFilesMetadata().isEmpty()); |
| 908 | + |
| 909 | + Index index2 = resolveIndex(index2Name); |
| 910 | + ShardId shardId2 = new ShardId(index2, 0); |
| 911 | + assertNodeStoreFilesMetadataSuccessCase(nodeStoreFilesMetadata.get(shardId2), shardId2); |
| 912 | + } |
| 913 | + |
| 914 | + private void prepareIndices(String[] indices, int numberOfPrimaryShards, int numberOfReplicaShards) { |
| 915 | + for (String index : indices) { |
| 916 | + createIndex( |
| 917 | + index, |
| 918 | + Settings.builder() |
| 919 | + .put(SETTING_NUMBER_OF_SHARDS, numberOfPrimaryShards) |
| 920 | + .put(SETTING_NUMBER_OF_REPLICAS, numberOfReplicaShards) |
| 921 | + .build() |
| 922 | + ); |
| 923 | + index(index, "type", "1", Collections.emptyMap()); |
| 924 | + flush(index); |
| 925 | + } |
| 926 | + } |
| 927 | + |
| 928 | + private TransportNodesListShardStoreMetadataBatch.NodesStoreFilesMetadataBatch prepareAndSendRequest( |
| 929 | + String[] indices, |
| 930 | + DiscoveryNode[] nodes |
| 931 | + ) { |
| 932 | + Map<ShardId, ShardAttributes> shardAttributesMap = null; |
| 933 | + prepareIndices(indices, 1, 1); |
| 934 | + shardAttributesMap = prepareRequestMap(indices, 1); |
| 935 | + TransportNodesListShardStoreMetadataBatch.NodesStoreFilesMetadataBatch response; |
| 936 | + return ActionTestUtils.executeBlocking( |
| 937 | + internalCluster().getInstance(TransportNodesListShardStoreMetadataBatch.class), |
| 938 | + new TransportNodesListShardStoreMetadataBatch.Request(shardAttributesMap, nodes) |
| 939 | + ); |
| 940 | + } |
| 941 | + |
| 942 | + private void assertNodeStoreFilesMetadataSuccessCase( |
| 943 | + TransportNodesListShardStoreMetadataBatch.NodeStoreFilesMetadata nodeStoreFilesMetadata, |
| 944 | + ShardId shardId |
| 945 | + ) { |
| 946 | + assertNull(nodeStoreFilesMetadata.getStoreFileFetchException()); |
| 947 | + TransportNodesListShardStoreMetadataHelper.StoreFilesMetadata storeFileMetadata = nodeStoreFilesMetadata.storeFilesMetadata(); |
| 948 | + assertFalse(storeFileMetadata.isEmpty()); |
| 949 | + assertEquals(shardId, storeFileMetadata.shardId()); |
| 950 | + assertNotNull(storeFileMetadata.peerRecoveryRetentionLeases()); |
| 951 | + } |
| 952 | + |
820 | 953 | private void assertNodeGatewayStartedShardsHappyCase(
|
821 | 954 | TransportNodesListGatewayStartedShardsBatch.NodeGatewayStartedShard nodeGatewayStartedShards
|
822 | 955 | ) {
|
|
0 commit comments