|
31 | 31 | import org.elasticsearch.action.admin.indices.recovery.RecoveryResponse; |
32 | 32 | import org.elasticsearch.action.admin.indices.stats.CommonStatsFlags; |
33 | 33 | import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; |
| 34 | +import org.elasticsearch.action.admin.indices.stats.ShardStats; |
34 | 35 | import org.elasticsearch.action.index.IndexRequestBuilder; |
35 | 36 | import org.elasticsearch.action.search.SearchResponse; |
36 | 37 | import org.elasticsearch.action.support.WriteRequest.RefreshPolicy; |
|
52 | 53 | import org.elasticsearch.index.analysis.TokenFilterFactory; |
53 | 54 | import org.elasticsearch.index.mapper.MapperParsingException; |
54 | 55 | import org.elasticsearch.index.recovery.RecoveryStats; |
| 56 | +import org.elasticsearch.index.seqno.SequenceNumbers; |
| 57 | +import org.elasticsearch.index.shard.ShardId; |
55 | 58 | import org.elasticsearch.index.store.Store; |
56 | 59 | import org.elasticsearch.indices.IndicesService; |
57 | 60 | import org.elasticsearch.indices.analysis.AnalysisModule; |
| 61 | +import org.elasticsearch.indices.flush.SyncedFlushUtil; |
58 | 62 | import org.elasticsearch.indices.recovery.RecoveryState.Stage; |
59 | 63 | import org.elasticsearch.node.RecoverySettingsChunkSizePlugin; |
60 | 64 | import org.elasticsearch.plugins.AnalysisPlugin; |
|
84 | 88 | import java.util.Collection; |
85 | 89 | import java.util.List; |
86 | 90 | import java.util.Map; |
| 91 | +import java.util.Set; |
87 | 92 | import java.util.concurrent.CountDownLatch; |
88 | 93 | import java.util.concurrent.ExecutionException; |
89 | 94 | import java.util.concurrent.Semaphore; |
90 | 95 | import java.util.concurrent.atomic.AtomicBoolean; |
91 | 96 | import java.util.concurrent.atomic.AtomicInteger; |
92 | 97 | import java.util.function.Consumer; |
| 98 | +import java.util.stream.Collectors; |
| 99 | +import java.util.stream.IntStream; |
| 100 | +import java.util.stream.Stream; |
93 | 101 |
|
94 | 102 | import static java.util.Collections.singletonMap; |
| 103 | +import static java.util.stream.Collectors.toList; |
95 | 104 | import static org.elasticsearch.node.RecoverySettingsChunkSizePlugin.CHUNK_SIZE_SETTING; |
96 | 105 | import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; |
97 | 106 | import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; |
@@ -910,6 +919,39 @@ public void testDoNotInfinitelyWaitForMapping() { |
910 | 919 | assertHitCount(client().prepareSearch().get(), numDocs); |
911 | 920 | } |
912 | 921 |
|
| 922 | + public void testRecoveryFlushReplica() throws Exception { |
| 923 | + internalCluster().ensureAtLeastNumDataNodes(3); |
| 924 | + String indexName = "test-index"; |
| 925 | + createIndex(indexName, Settings.builder().put("index.number_of_replicas", 0).put("index.number_of_shards", 1).build()); |
| 926 | + int numDocs = randomIntBetween(0, 10); |
| 927 | + indexRandom(randomBoolean(), false, randomBoolean(), IntStream.range(0, numDocs) |
| 928 | + .mapToObj(n -> client().prepareIndex(indexName, "_doc").setSource("num", n)).collect(toList())); |
| 929 | + assertAcked(client().admin().indices().prepareUpdateSettings(indexName) |
| 930 | + .setSettings(Settings.builder().put("index.number_of_replicas", 1))); |
| 931 | + ensureGreen(indexName); |
| 932 | + ShardId shardId = null; |
| 933 | + for (ShardStats shardStats : client().admin().indices().prepareStats(indexName).get().getIndex(indexName).getShards()) { |
| 934 | + shardId = shardStats.getShardRouting().shardId(); |
| 935 | + if (shardStats.getShardRouting().primary() == false) { |
| 936 | + assertThat(shardStats.getCommitStats().getNumDocs(), equalTo(numDocs)); |
| 937 | + SequenceNumbers.CommitInfo commitInfo = SequenceNumbers.loadSeqNoInfoFromLuceneCommit( |
| 938 | + shardStats.getCommitStats().getUserData().entrySet()); |
| 939 | + assertThat(commitInfo.localCheckpoint, equalTo(shardStats.getSeqNoStats().getLocalCheckpoint())); |
| 940 | + assertThat(commitInfo.maxSeqNo, equalTo(shardStats.getSeqNoStats().getMaxSeqNo())); |
| 941 | + } |
| 942 | + } |
| 943 | + SyncedFlushUtil.attemptSyncedFlush(logger, internalCluster(), shardId); |
| 944 | + assertBusy(() -> assertThat(client().admin().indices().prepareSyncedFlush(indexName).get().failedShards(), equalTo(0))); |
| 945 | + assertAcked(client().admin().indices().prepareUpdateSettings(indexName) |
| 946 | + .setSettings(Settings.builder().put("index.number_of_replicas", 2))); |
| 947 | + ensureGreen(indexName); |
| 948 | + // Recovery should keep syncId if no indexing activity on the primary after synced-flush. |
| 949 | + Set<String> syncIds = Stream.of(client().admin().indices().prepareStats(indexName).get().getIndex(indexName).getShards()) |
| 950 | + .map(shardStats -> shardStats.getCommitStats().syncId()) |
| 951 | + .collect(Collectors.toSet()); |
| 952 | + assertThat(syncIds, hasSize(1)); |
| 953 | + } |
| 954 | + |
913 | 955 | public static final class TestAnalysisPlugin extends Plugin implements AnalysisPlugin { |
914 | 956 | final AtomicBoolean throwParsingError = new AtomicBoolean(); |
915 | 957 | @Override |
|
0 commit comments