diff --git a/core/src/main/java/org/elasticsearch/indices/IndicesService.java b/core/src/main/java/org/elasticsearch/indices/IndicesService.java index 48973bca5bd..61aaf551610 100644 --- a/core/src/main/java/org/elasticsearch/indices/IndicesService.java +++ b/core/src/main/java/org/elasticsearch/indices/IndicesService.java @@ -681,8 +681,8 @@ public class IndicesService extends AbstractLifecycleComponent i */ @Nullable public IndexMetaData verifyIndexIsDeleted(final Index index, final ClusterState clusterState) { - // this method should only be called when we know the index is not part of the cluster state - if (clusterState.metaData().hasIndex(index.getName())) { + // this method should only be called when we know the index (name + uuid) is not part of the cluster state + if (clusterState.metaData().index(index) != null) { throw new IllegalStateException("Cannot delete index [" + index + "], it is still part of the cluster state."); } if (nodeEnv.hasNodeFile() && FileSystemUtils.exists(nodeEnv.indexPaths(index))) { diff --git a/core/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java b/core/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java index 02c415c247a..76f7a30e078 100644 --- a/core/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java +++ b/core/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java @@ -21,8 +21,10 @@ package org.elasticsearch.indices; import org.apache.lucene.store.LockObtainFailedException; import org.elasticsearch.Version; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.AliasAction; +import org.elasticsearch.cluster.metadata.IndexGraveyard; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.service.ClusterService; @@ -283,6 +285,36 @@ public class IndicesServiceTests extends ESSingleNodeTestCase { indicesService.deleteIndex(test.index(), "finished with test"); } + /** + * This test checks an edge case where, if a node had an index (lets call it A with UUID 1), then + * deleted it (so a tombstone entry for A will exist in the cluster state), then created + * a new index A with UUID 2, then shutdown, when the node comes back online, it will look at the + * tombstones for deletions, and it should proceed with trying to delete A with UUID 1 and not + * throw any errors that the index still exists in the cluster state. This is a case of ensuring + * that tombstones that have the same name as current valid indices don't cause confusion by + * trying to delete an index that exists. + * See https://github.com/elastic/elasticsearch/issues/18054 + */ + public void testIndexAndTombstoneWithSameNameOnStartup() throws Exception { + final String indexName = "test"; + final Index index = new Index(indexName, UUIDs.randomBase64UUID()); + final IndicesService indicesService = getIndicesService(); + final Settings idxSettings = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) + .put(IndexMetaData.SETTING_INDEX_UUID, index.getUUID()) + .build(); + final IndexMetaData indexMetaData = new IndexMetaData.Builder(index.getName()) + .settings(idxSettings) + .numberOfShards(1) + .numberOfReplicas(0) + .build(); + final Index tombstonedIndex = new Index(indexName, UUIDs.randomBase64UUID()); + final IndexGraveyard graveyard = IndexGraveyard.builder().addTombstone(tombstonedIndex).build(); + final MetaData metaData = MetaData.builder().put(indexMetaData, true).indexGraveyard(graveyard).build(); + final ClusterState clusterState = new ClusterState.Builder(new ClusterName("testCluster")).metaData(metaData).build(); + // if all goes well, this won't throw an exception, otherwise, it will throw an IllegalStateException + indicesService.verifyIndexIsDeleted(tombstonedIndex, clusterState); + } + private static class DanglingListener implements LocalAllocateDangledIndices.Listener { final CountDownLatch latch = new CountDownLatch(1);