DanglingIndicesIT.java 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * Licensed to Elasticsearch under one or more contributor
  3. * license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright
  5. * ownership. Elasticsearch licenses this file to you under
  6. * the Apache License, Version 2.0 (the "License"); you may
  7. * not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. package org.elasticsearch.indices.recovery;
  20. import org.elasticsearch.common.settings.Settings;
  21. import org.elasticsearch.indices.IndicesService;
  22. import org.elasticsearch.test.ESIntegTestCase;
  23. import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
  24. import org.elasticsearch.test.InternalTestCluster;
  25. import java.util.concurrent.TimeUnit;
  26. import static org.elasticsearch.cluster.metadata.IndexGraveyard.SETTING_MAX_TOMBSTONES;
  27. import static org.elasticsearch.gateway.DanglingIndicesState.AUTO_IMPORT_DANGLING_INDICES_SETTING;
  28. import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
  29. import static org.hamcrest.Matchers.equalTo;
  30. @ClusterScope(numDataNodes = 0, scope = ESIntegTestCase.Scope.TEST)
  31. public class DanglingIndicesIT extends ESIntegTestCase {
  32. private static final String INDEX_NAME = "test-idx-1";
  33. private Settings buildSettings(boolean writeDanglingIndices, boolean importDanglingIndices) {
  34. return Settings.builder()
  35. // Don't keep any indices in the graveyard, so that when we delete an index,
  36. // it's definitely considered to be dangling.
  37. .put(SETTING_MAX_TOMBSTONES.getKey(), 0)
  38. .put(IndicesService.WRITE_DANGLING_INDICES_INFO_SETTING.getKey(), writeDanglingIndices)
  39. .put(AUTO_IMPORT_DANGLING_INDICES_SETTING.getKey(), importDanglingIndices)
  40. .build();
  41. }
  42. /**
  43. * Check that when dangling indices are discovered, then they are recovered into
  44. * the cluster, so long as the recovery setting is enabled.
  45. */
  46. public void testDanglingIndicesAreRecoveredWhenSettingIsEnabled() throws Exception {
  47. final Settings settings = buildSettings(true, true);
  48. internalCluster().startNodes(3, settings);
  49. createIndex(INDEX_NAME, Settings.builder().put("number_of_replicas", 2).build());
  50. ensureGreen(INDEX_NAME);
  51. assertBusy(() -> internalCluster().getInstances(IndicesService.class).forEach(
  52. indicesService -> assertTrue(indicesService.allPendingDanglingIndicesWritten())));
  53. boolean refreshIntervalChanged = randomBoolean();
  54. if (refreshIntervalChanged) {
  55. client().admin().indices().prepareUpdateSettings(INDEX_NAME).setSettings(
  56. Settings.builder().put("index.refresh_interval", "42s").build()).get();
  57. assertBusy(() -> internalCluster().getInstances(IndicesService.class).forEach(
  58. indicesService -> assertTrue(indicesService.allPendingDanglingIndicesWritten())));
  59. }
  60. if (randomBoolean()) {
  61. client().admin().indices().prepareClose(INDEX_NAME).get();
  62. }
  63. ensureGreen(INDEX_NAME);
  64. // Restart node, deleting the index in its absence, so that there is a dangling index to recover
  65. internalCluster().restartRandomDataNode(new InternalTestCluster.RestartCallback() {
  66. @Override
  67. public Settings onNodeStopped(String nodeName) throws Exception {
  68. ensureClusterSizeConsistency();
  69. assertAcked(client().admin().indices().prepareDelete(INDEX_NAME));
  70. return super.onNodeStopped(nodeName);
  71. }
  72. });
  73. assertBusy(() -> assertTrue("Expected dangling index " + INDEX_NAME + " to be recovered", indexExists(INDEX_NAME)));
  74. if (refreshIntervalChanged) {
  75. assertThat(client().admin().indices().prepareGetSettings(INDEX_NAME).get().getSetting(INDEX_NAME, "index.refresh_interval"),
  76. equalTo("42s"));
  77. }
  78. ensureGreen(INDEX_NAME);
  79. }
  80. /**
  81. * Check that when dangling indices are discovered, then they are not recovered into
  82. * the cluster when the recovery setting is disabled.
  83. */
  84. public void testDanglingIndicesAreNotRecoveredWhenSettingIsDisabled() throws Exception {
  85. internalCluster().startNodes(3, buildSettings(true, false));
  86. createIndex(INDEX_NAME, Settings.builder().put("number_of_replicas", 2).build());
  87. ensureGreen(INDEX_NAME);
  88. assertBusy(() -> internalCluster().getInstances(IndicesService.class).forEach(
  89. indicesService -> assertTrue(indicesService.allPendingDanglingIndicesWritten())));
  90. // Restart node, deleting the index in its absence, so that there is a dangling index to recover
  91. internalCluster().restartRandomDataNode(new InternalTestCluster.RestartCallback() {
  92. @Override
  93. public Settings onNodeStopped(String nodeName) throws Exception {
  94. ensureClusterSizeConsistency();
  95. assertAcked(client().admin().indices().prepareDelete(INDEX_NAME));
  96. return super.onNodeStopped(nodeName);
  97. }
  98. });
  99. // Since index recovery is async, we can't prove index recovery will never occur, just that it doesn't occur within some reasonable
  100. // amount of time
  101. assertFalse(
  102. "Did not expect dangling index " + INDEX_NAME + " to be recovered",
  103. waitUntil(() -> indexExists(INDEX_NAME), 1, TimeUnit.SECONDS)
  104. );
  105. }
  106. /**
  107. * Check that when dangling indices are not written, then they cannot be recovered into the cluster.
  108. */
  109. public void testDanglingIndicesAreNotRecoveredWhenNotWritten() throws Exception {
  110. internalCluster().startNodes(3, buildSettings(false, true));
  111. createIndex(INDEX_NAME, Settings.builder().put("number_of_replicas", 2).build());
  112. ensureGreen(INDEX_NAME);
  113. internalCluster().getInstances(IndicesService.class).forEach(
  114. indicesService -> assertTrue(indicesService.allPendingDanglingIndicesWritten()));
  115. // Restart node, deleting the index in its absence, so that there is a dangling index to recover
  116. internalCluster().restartRandomDataNode(new InternalTestCluster.RestartCallback() {
  117. @Override
  118. public Settings onNodeStopped(String nodeName) throws Exception {
  119. ensureClusterSizeConsistency();
  120. assertAcked(client().admin().indices().prepareDelete(INDEX_NAME));
  121. return super.onNodeStopped(nodeName);
  122. }
  123. });
  124. // Since index recovery is async, we can't prove index recovery will never occur, just that it doesn't occur within some reasonable
  125. // amount of time
  126. assertFalse(
  127. "Did not expect dangling index " + INDEX_NAME + " to be recovered",
  128. waitUntil(() -> indexExists(INDEX_NAME), 1, TimeUnit.SECONDS)
  129. );
  130. }
  131. }