From 45113827c29c36cda82f32624aa9c4f9da02db87 Mon Sep 17 00:00:00 2001 From: Ali Beyad Date: Thu, 28 Apr 2016 23:50:49 -0400 Subject: [PATCH] When checking if an index tombstone can be applied, use both the index name and uuid because the cluster state may contain an active index of the same name (but different uuid). Closes #18058 Closes #18054 --- .../elasticsearch/indices/IndicesService.java | 4 +-- .../indices/IndicesServiceTests.java | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/indices/IndicesService.java b/core/src/main/java/org/elasticsearch/indices/IndicesService.java index 48973bca5bd15..61aaf55161092 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 boolean canDeleteIndexContents(Index index, IndexSettings indexSettings) */ @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 02c415c247a57..76f7a30e0788a 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 @@ 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 void testDanglingIndicesWithAliasConflict() throws Exception { 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);