Skip to content

Commit

Permalink
Require manifest file for upgrades to v8
Browse files Browse the repository at this point in the history
7.x nodes permit the on-disk cluster metadata to omit the manifest file in
order to support upgrades from 6.x. We are similarly lenient in `master`, i.e.
8.x, but there is no need to be since we must be upgrading from a 7.x node
which ensures that the manifest file is written.

This commit removes the lenient loading of a manifest-free cluster metadata
from `master`.

Relates elastic#38556
  • Loading branch information
DaveCTurner committed Feb 17, 2020
1 parent 403d1ff commit a015ad7
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.cluster.metadata.IndexGraveyard;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.Manifest;
import org.elasticsearch.cluster.metadata.MetaData;
Expand All @@ -33,9 +33,10 @@

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

/**
Expand Down Expand Up @@ -71,7 +72,27 @@ public MetaStateService(NodeEnvironment nodeEnv, NamedXContentRegistry namedXCon
public Tuple<Manifest, MetaData> loadFullState() throws IOException {
final Manifest manifest = MANIFEST_FORMAT.loadLatestState(logger, namedXContentRegistry, nodeEnv.nodeDataPaths());
if (manifest == null) {
return loadFullStateBWC();
if (META_DATA_FORMAT.loadLatestState(logger, namedXContentRegistry, nodeEnv.nodeDataPaths()) != null) {
// not mentioning version constants explicitly since we already assert that this code is dead from v9 onwards
throw new IllegalStateException("found on-disk global metadata from a cluster of version 6.x or earlier; you must first " +
"upgrade this node to a 7.x version before you can upgrade it to version " + Version.CURRENT);
}
final Set<Index> indices = new HashSet<>();
for (String indexFolder : nodeEnv.availableIndexFolders()) {
final IndexMetaData indexMetadata
= INDEX_META_DATA_FORMAT.loadLatestState(logger, namedXContentRegistry, nodeEnv.resolveIndexFolder(indexFolder));
if (indexMetadata != null) {
indices.add(indexMetadata.getIndex());
}
}

if (indices.isEmpty() == false) {
// not mentioning version constants explicitly since we already assert that this code is dead from v9 onwards
throw new IllegalStateException("found on-disk index metadata from a cluster of version 6.x or earlier for indices " +
indices + "; you must first upgrade this node to a 7.x version before you can upgrade it to version " +
Version.CURRENT);
}
return Tuple.tuple(Manifest.empty(), MetaData.builder().build());
}

final MetaData.Builder metaDataBuilder;
Expand Down Expand Up @@ -104,54 +125,6 @@ public Tuple<Manifest, MetaData> loadFullState() throws IOException {
return new Tuple<>(manifest, metaDataBuilder.build());
}

/**
* "Manifest-less" BWC version of loading metadata from disk. See also {@link #loadFullState()}
*/
private Tuple<Manifest, MetaData> loadFullStateBWC() throws IOException {
Map<Index, Long> indices = new HashMap<>();
MetaData.Builder metaDataBuilder;

Tuple<MetaData, Long> metaDataAndGeneration =
META_DATA_FORMAT.loadLatestStateWithGeneration(logger, namedXContentRegistry, nodeEnv.nodeDataPaths());
MetaData globalMetaData = metaDataAndGeneration.v1();
long globalStateGeneration = metaDataAndGeneration.v2();

final IndexGraveyard indexGraveyard;
if (globalMetaData != null) {
metaDataBuilder = MetaData.builder(globalMetaData);
indexGraveyard = globalMetaData.custom(IndexGraveyard.TYPE);
// TODO https://github.com/elastic/elasticsearch/issues/38556
// assert Version.CURRENT.major < 8 : "failed to find manifest file, which is mandatory staring with Elasticsearch version 8.0";
} else {
metaDataBuilder = MetaData.builder();
indexGraveyard = IndexGraveyard.builder().build();
}

for (String indexFolderName : nodeEnv.availableIndexFolders()) {
Tuple<IndexMetaData, Long> indexMetaDataAndGeneration =
INDEX_META_DATA_FORMAT.loadLatestStateWithGeneration(logger, namedXContentRegistry,
nodeEnv.resolveIndexFolder(indexFolderName));
// TODO https://github.com/elastic/elasticsearch/issues/38556
// assert Version.CURRENT.major < 8 : "failed to find manifest file, which is mandatory staring with Elasticsearch version 8.0";
IndexMetaData indexMetaData = indexMetaDataAndGeneration.v1();
long generation = indexMetaDataAndGeneration.v2();
if (indexMetaData != null) {
if (indexGraveyard.containsIndex(indexMetaData.getIndex())) {
logger.debug("[{}] found metadata for deleted index [{}]", indexFolderName, indexMetaData.getIndex());
// this index folder is cleared up when state is recovered
} else {
indices.put(indexMetaData.getIndex(), generation);
metaDataBuilder.put(indexMetaData, false);
}
} else {
logger.debug("[{}] failed to find metadata for existing index location", indexFolderName);
}
}

Manifest manifest = Manifest.unknownCurrentTermAndVersion(globalStateGeneration, indices);
return new Tuple<>(manifest, metaDataBuilder.build());
}

/**
* Loads the index state for the provided index name, returning null if doesn't exists.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -506,44 +506,6 @@ public void testArchiveBrokenClusterSettings() throws Exception {
assertHitCount(client().prepareSearch().setQuery(matchAllQuery()).get(), 1L);
}

@AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/48701")
// This test relates to loading a broken state that was written by a 6.x node, but for now we do not load state from old nodes.
public void testHalfDeletedIndexImport() throws Exception {
// It's possible for a 6.x node to add a tombstone for an index but not actually delete the index metadata from disk since that
// deletion is slightly deferred and may race against the node being shut down; if you upgrade to 7.x when in this state then the
// node won't start.

internalCluster().startNode();
createIndex("test", Settings.builder()
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)
.build());
ensureGreen("test");

final MetaData metaData = internalCluster().getInstance(ClusterService.class).state().metaData();
final Path[] paths = internalCluster().getInstance(NodeEnvironment.class).nodeDataPaths();
// writeBrokenMeta(metaStateService -> {
// metaStateService.writeGlobalState("test", MetaData.builder(metaData)
// // we remove the manifest file, resetting the term and making this look like an upgrade from 6.x, so must also reset the
// // term in the coordination metadata
// .coordinationMetaData(CoordinationMetaData.builder(metaData.coordinationMetaData()).term(0L).build())
// // add a tombstone but do not delete the index metadata from disk
// .putCustom(IndexGraveyard.TYPE, IndexGraveyard.builder().addTombstone(metaData.index("test").getIndex()).build()).build());
// for (final Path path : paths) {
// try (Stream<Path> stateFiles = Files.list(path.resolve(MetaDataStateFormat.STATE_DIR_NAME))) {
// for (final Path manifestPath : stateFiles
// .filter(p -> p.getFileName().toString().startsWith(Manifest.FORMAT.getPrefix())).collect(Collectors.toList())) {
// IOUtils.rm(manifestPath);
// }
// }
// }
// });

ensureGreen();

assertBusy(() -> assertThat(internalCluster().getInstance(NodeEnvironment.class).availableIndexFolders(), empty()));
}

private void restartNodesOnBrokenClusterState(ClusterState.Builder clusterStateBuilder) throws Exception {
Map<String, PersistedClusterStateService> lucenePersistedStateFactories = Stream.of(internalCluster().getNodeNames())
.collect(Collectors.toMap(Function.identity(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@
import java.io.IOException;
import java.util.HashMap;

import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.nullValue;

public class MetaStateServiceTests extends ESTestCase {
Expand Down Expand Up @@ -95,26 +96,26 @@ public void testWriteGlobalStateWithIndexAndNoIndexIsLoaded() throws Exception {
assertThat(metaStateService.loadGlobalState().hasIndex("test1"), equalTo(false));
}

public void testLoadFullStateBWC() throws Exception {
IndexMetaData indexMetaData = indexMetaData("test1");
public void testLoadFullStateRejectsGlobalMetadataWithoutManifest() throws Exception {
MetaData metaData = MetaData.builder()
.persistentSettings(Settings.builder().put("test1", "value1").build())
.put(indexMetaData, true)
.build();
.persistentSettings(Settings.builder().put("test1", "value1").build())
.build();

long globalGeneration = metaStateService.writeGlobalState("test_write", metaData);
long indexGeneration = metaStateService.writeIndex("test_write", indexMetaData);
metaStateService.writeGlobalState("test_write", metaData);

Tuple<Manifest, MetaData> manifestAndMetaData = metaStateService.loadFullState();
Manifest manifest = manifestAndMetaData.v1();
assertThat(manifest.getGlobalGeneration(), equalTo(globalGeneration));
assertThat(manifest.getIndexGenerations(), hasKey(indexMetaData.getIndex()));
assertThat(manifest.getIndexGenerations().get(indexMetaData.getIndex()), equalTo(indexGeneration));
assertThat(expectThrows(IllegalStateException.class, metaStateService::loadFullState).getMessage(),
containsString("found on-disk global metadata from a cluster of version 6.x or earlier; you must first upgrade this node to " +
"a 7.x version before you can upgrade it to version " + Version.CURRENT));
}

MetaData loadedMetaData = manifestAndMetaData.v2();
assertThat(loadedMetaData.persistentSettings(), equalTo(metaData.persistentSettings()));
assertThat(loadedMetaData.hasIndex("test1"), equalTo(true));
assertThat(loadedMetaData.index("test1"), equalTo(indexMetaData));
public void testLoadFullStateRejectsIndexMetadataWithoutManifest() throws Exception {
IndexMetaData indexMetaData = indexMetaData("test1");
metaStateService.writeIndex("test_write", indexMetaData);

assertThat(expectThrows(IllegalStateException.class, metaStateService::loadFullState).getMessage(), allOf(
containsString("found on-disk index metadata from a cluster of version 6.x or earlier for indices ["),
containsString(indexMetaData.getIndex().toString()),
containsString("you must first upgrade this node to a 7.x version before you can upgrade it to version " + Version.CURRENT)));
}

public void testLoadEmptyStateNoManifest() throws IOException {
Expand Down

0 comments on commit a015ad7

Please sign in to comment.