|
36 | 36 | import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptResponse; |
37 | 37 | import org.elasticsearch.action.admin.indices.flush.FlushResponse; |
38 | 38 | import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse; |
| 39 | +import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; |
39 | 40 | import org.elasticsearch.action.admin.indices.stats.ShardStats; |
40 | 41 | import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse; |
41 | 42 | import org.elasticsearch.action.index.IndexRequestBuilder; |
|
71 | 72 | import org.elasticsearch.common.unit.TimeValue; |
72 | 73 | import org.elasticsearch.common.xcontent.XContentFactory; |
73 | 74 | import org.elasticsearch.common.xcontent.XContentType; |
| 75 | +import org.elasticsearch.index.Index; |
74 | 76 | import org.elasticsearch.index.IndexService; |
75 | 77 | import org.elasticsearch.index.engine.Engine; |
| 78 | +import org.elasticsearch.index.shard.IndexShard; |
76 | 79 | import org.elasticsearch.index.shard.ShardId; |
77 | 80 | import org.elasticsearch.indices.IndicesService; |
78 | 81 | import org.elasticsearch.indices.InvalidIndexNameException; |
|
112 | 115 | import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; |
113 | 116 | import static org.elasticsearch.index.IndexSettings.INDEX_REFRESH_INTERVAL_SETTING; |
114 | 117 | import static org.elasticsearch.index.query.QueryBuilders.matchQuery; |
| 118 | +import static org.elasticsearch.index.shard.IndexShardTests.getEngineFromShard; |
115 | 119 | import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; |
116 | 120 | import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAliasesExist; |
117 | 121 | import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAliasesMissing; |
@@ -3072,6 +3076,73 @@ public void testGetSnapshotsFromIndexBlobOnly() throws Exception { |
3072 | 3076 | } |
3073 | 3077 | } |
3074 | 3078 |
|
| 3079 | + public void testSnapshottingWithMissingSequenceNumbers() { |
| 3080 | + final String repositoryName = "test-repo"; |
| 3081 | + final String snapshotName = "test-snap"; |
| 3082 | + final String indexName = "test-idx"; |
| 3083 | + final Client client = client(); |
| 3084 | + final Path repo = randomRepoPath(); |
| 3085 | + |
| 3086 | + logger.info("--> creating repository at {}", repo.toAbsolutePath()); |
| 3087 | + assertAcked(client.admin().cluster().preparePutRepository(repositoryName) |
| 3088 | + .setType("fs").setSettings(Settings.builder() |
| 3089 | + .put("location", repo) |
| 3090 | + .put("compress", false) |
| 3091 | + .put("chunk_size", randomIntBetween(100, 1000), ByteSizeUnit.BYTES))); |
| 3092 | + logger.info("--> creating an index and indexing documents"); |
| 3093 | + final String dataNode = internalCluster().getDataNodeInstance(ClusterService.class).localNode().getName(); |
| 3094 | + final Settings settings = |
| 3095 | + Settings |
| 3096 | + .builder() |
| 3097 | + .put("index.number_of_shards", 1) |
| 3098 | + .put("index.number_of_replicas", 0) |
| 3099 | + .put("index.routing.allocation.include._name", dataNode) |
| 3100 | + .build(); |
| 3101 | + createIndex(indexName, settings); |
| 3102 | + ensureGreen(); |
| 3103 | + for (int i = 0; i < 5; i++) { |
| 3104 | + index(indexName, "_doc", Integer.toString(i), "foo", "bar" + i); |
| 3105 | + } |
| 3106 | + |
| 3107 | + final Index index = resolveIndex(indexName); |
| 3108 | + final IndexShard primary = internalCluster().getInstance(IndicesService.class, dataNode).getShardOrNull(new ShardId(index, 0)); |
| 3109 | + // create a gap in the sequence numbers |
| 3110 | + getEngineFromShard(primary).seqNoService().generateSeqNo(); |
| 3111 | + |
| 3112 | + for (int i = 5; i < 10; i++) { |
| 3113 | + index(indexName, "_doc", Integer.toString(i), "foo", "bar" + i); |
| 3114 | + } |
| 3115 | + |
| 3116 | + refresh(); |
| 3117 | + |
| 3118 | + logger.info("--> snapshot"); |
| 3119 | + CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot(repositoryName, snapshotName) |
| 3120 | + .setWaitForCompletion(true).setIndices(indexName).get(); |
| 3121 | + assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0)); |
| 3122 | + assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), |
| 3123 | + equalTo(createSnapshotResponse.getSnapshotInfo().totalShards())); |
| 3124 | + |
| 3125 | + logger.info("--> delete indices"); |
| 3126 | + assertAcked(client.admin().indices().prepareDelete(indexName)); |
| 3127 | + |
| 3128 | + logger.info("--> restore all indices from the snapshot"); |
| 3129 | + RestoreSnapshotResponse restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap") |
| 3130 | + .setWaitForCompletion(true).execute().actionGet(); |
| 3131 | + assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0)); |
| 3132 | + |
| 3133 | + logger.info("--> indexing some more"); |
| 3134 | + for (int i = 10; i < 15; i++) { |
| 3135 | + index(indexName, "_doc", Integer.toString(i), "foo", "bar" + i); |
| 3136 | + } |
| 3137 | + |
| 3138 | + IndicesStatsResponse stats = client().admin().indices().prepareStats(indexName).clear().get(); |
| 3139 | + ShardStats shardStats = stats.getShards()[0]; |
| 3140 | + assertTrue(shardStats.getShardRouting().primary()); |
| 3141 | + assertThat(shardStats.getSeqNoStats().getLocalCheckpoint(), equalTo(15L)); // 15 indexed docs and one "missing" op. |
| 3142 | + assertThat(shardStats.getSeqNoStats().getGlobalCheckpoint(), equalTo(15L)); |
| 3143 | + assertThat(shardStats.getSeqNoStats().getMaxSeqNo(), equalTo(15L)); |
| 3144 | + } |
| 3145 | + |
3075 | 3146 | private void verifySnapshotInfo(final GetSnapshotsResponse response, final Map<String, List<String>> indicesPerSnapshot) { |
3076 | 3147 | for (SnapshotInfo snapshotInfo : response.getSnapshots()) { |
3077 | 3148 | final List<String> expected = snapshotInfo.indices(); |
|
0 commit comments