Remove MDP from PersistedClusterStateService#72278
Conversation
This commit removes multiple data path support from the PersistedClusterStateService. Most notably, many error cases are no longer possible where duplicate/conflicting data could previously exist across multiple paths, there is now only one path. relates elastic#71205
|
Pinging @elastic/es-core-infra (Team:Core/Infra) |
|
Note that to avoid an enormous PR removing MDP support, this PR tries to narrowly remove support from a single service. There are many examples where the calling code creates a service for testing with multiple paths, but just uses the first path. This is ok for as an intermediate step since we already block any actual uses of MDP in real nodes. |
DaveCTurner
left a comment
There was a problem hiding this comment.
This is ok for as an intermediate step since we already block any actual uses of MDP in real nodes.
I left a suggestion at https://github.com/elastic/elasticsearch/pull/72282/files#r621070239 for making this clearer from the code, and a few other observations.
| final Metadata metadata = Metadata.Builder.fromXContent(XContentFactory.xContent(XContentType.SMILE) | ||
| .createParser(namedXContentRegistry, LoggingDeprecationHandler.INSTANCE, bytes.bytes, bytes.offset, bytes.length)); | ||
| logger.trace("found global metadata with last-accepted term [{}]", metadata.coordinationMetadata().term()); | ||
| if (builderReference.get() != null) { |
There was a problem hiding this comment.
This change seems unrelated, it's here to catch a case where someone meddled with the metadata and left us with two copies of the global metadata in the same data path. I think we should keep this.
| final IndexMetadata indexMetadata = IndexMetadata.fromXContent(XContentFactory.xContent(XContentType.SMILE) | ||
| .createParser(namedXContentRegistry, LoggingDeprecationHandler.INSTANCE, bytes.bytes, bytes.offset, bytes.length)); | ||
| logger.trace("found index metadata for {}", indexMetadata.getIndex()); | ||
| if (indexUUIDs.add(indexMetadata.getIndexUUID()) == false) { |
There was a problem hiding this comment.
This change seems unrelated, it's here to catch a case where someone meddled with the metadata and left us with two copies of the metadata for the same index in the same data path. I think we should keep this.
| } | ||
| } | ||
|
|
||
| public void testFailsIfGlobalMetadataIsDuplicated() throws IOException { |
There was a problem hiding this comment.
This test is still meaningful, although we'll need to work out a more creative way to duplicate that document.
There was a problem hiding this comment.
Here is the same test but using two distinct NodeEnvironment objects to get the metadata indices that we mash together. This works on master as it stands today, obviously needs adjusting for the single-data-path case.
public void testFailsIfGlobalMetadataIsDuplicated() throws IOException {
// if someone attempted surgery on the metadata index by hand, e.g. deleting broken segments, then maybe the global metadata
// is duplicated
final Path[] dataPaths1 = createDataPaths();
final Path[] dataPaths2 = createDataPaths();
try (NodeEnvironment nodeEnvironment1 = newNodeEnvironment(dataPaths1);
NodeEnvironment nodeEnvironment2 = newNodeEnvironment(dataPaths2)) {
try (Writer writer1 = newPersistedClusterStateService(nodeEnvironment1).createWriter();
Writer writer2 = newPersistedClusterStateService(nodeEnvironment2).createWriter()) {
final ClusterState oldClusterState = loadPersistedClusterState(newPersistedClusterStateService(nodeEnvironment1));
final long newVersion = randomLongBetween(1L, Long.MAX_VALUE);
final ClusterState newClusterState = ClusterState.builder(oldClusterState).version(newVersion).build();
writeState(writer1, 0L, newClusterState, oldClusterState);
writeState(writer2, 0L, newClusterState, oldClusterState);
}
final Path brokenPath = randomFrom(nodeEnvironment1.nodeDataPaths());
final Path dupPath = randomFrom(nodeEnvironment2.nodeDataPaths());
try (Directory directory = new SimpleFSDirectory(brokenPath.resolve(PersistedClusterStateService.METADATA_DIRECTORY_NAME));
Directory dupDirectory = new SimpleFSDirectory(dupPath.resolve(PersistedClusterStateService.METADATA_DIRECTORY_NAME))) {
try (IndexWriter indexWriter = new IndexWriter(directory, new IndexWriterConfig())) {
indexWriter.addIndexes(dupDirectory);
indexWriter.commit();
}
}
final String message = expectThrows(IllegalStateException.class,
() -> newPersistedClusterStateService(nodeEnvironment1).loadBestOnDiskState()).getMessage();
assertThat(message, allOf(containsString("duplicate global metadata found"), containsString(brokenPath.toString())));
}
}
| } | ||
| } | ||
|
|
||
| public void testFailsIfIndexMetadataIsDuplicated() throws IOException { |
There was a problem hiding this comment.
This test is still meaningful, although we'll need to work out a more creative way to duplicate that document.
There was a problem hiding this comment.
Here is the same test but using two distinct NodeEnvironment objects to get the metadata indices that we mash together. This works on master as it stands today, obviously needs adjusting for the single-data-path case.
public void testFailsIfIndexMetadataIsDuplicated() throws IOException {
// if someone attempted surgery on the metadata index by hand, e.g. deleting broken segments, then maybe some index metadata
// is duplicated
final Path[] dataPaths1 = createDataPaths();
final Path[] dataPaths2 = createDataPaths();
try (NodeEnvironment nodeEnvironment1 = newNodeEnvironment(dataPaths1);
NodeEnvironment nodeEnvironment2 = newNodeEnvironment(dataPaths2)) {
final String indexUUID = UUIDs.randomBase64UUID(random());
final String indexName = randomAlphaOfLength(10);
try (Writer writer1 = newPersistedClusterStateService(nodeEnvironment1).createWriter();
Writer writer2 = newPersistedClusterStateService(nodeEnvironment2).createWriter()) {
final ClusterState oldClusterState = loadPersistedClusterState(newPersistedClusterStateService(nodeEnvironment1));
final ClusterState newClusterState = ClusterState.builder(oldClusterState)
.metadata(Metadata.builder(oldClusterState.metadata())
.version(1L)
.coordinationMetadata(CoordinationMetadata.builder(oldClusterState.coordinationMetadata()).term(1L).build())
.put(IndexMetadata.builder(indexName)
.version(1L)
.settings(Settings.builder()
.put(IndexMetadata.INDEX_NUMBER_OF_SHARDS_SETTING.getKey(), 1)
.put(IndexMetadata.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey(), 0)
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetadata.SETTING_INDEX_UUID, indexUUID))))
.incrementVersion().build();
writeState(writer1, 0L, newClusterState, oldClusterState);
writeState(writer2, 0L, newClusterState, oldClusterState);
}
final Path brokenPath = randomFrom(nodeEnvironment1.nodeDataPaths());
final Path dupPath = randomFrom(nodeEnvironment2.nodeDataPaths());
try (Directory directory = new SimpleFSDirectory(brokenPath.resolve(PersistedClusterStateService.METADATA_DIRECTORY_NAME));
Directory dupDirectory = new SimpleFSDirectory(dupPath.resolve(PersistedClusterStateService.METADATA_DIRECTORY_NAME))) {
try (IndexWriter indexWriter = new IndexWriter(directory, new IndexWriterConfig())) {
indexWriter.deleteDocuments(new Term("type", "global")); // do not duplicate global metadata
indexWriter.addIndexes(dupDirectory);
indexWriter.commit();
}
}
final String message = expectThrows(IllegalStateException.class,
() -> newPersistedClusterStateService(nodeEnvironment1).loadBestOnDiskState()).getMessage();
assertThat(message, allOf(
containsString("duplicate metadata found"),
containsString(brokenPath.toString()),
containsString(indexName),
containsString(indexUUID)));
}
}
The path.data setting is now a singular string, but the method dataFiles() that gives access to the path is still an array. This commit renames the method and makes the return type a single Path. relates elastic#71205
|
Thanks for laying out the modified tests @DaveCTurner. I've added them back as suggested. I think this PR is ready for review again. |
DaveCTurner
left a comment
There was a problem hiding this comment.
LGTM, I noted scope for one tiny extra cleanup too but no need for another round.
| nodePaths = new Path[] { nodeEnvironment.nodeDataPath() }; | ||
| final String nodeId = randomAlphaOfLength(10); | ||
| try (PersistedClusterStateService.Writer writer = new PersistedClusterStateService(nodePaths, nodeId, | ||
| try (PersistedClusterStateService.Writer writer = new PersistedClusterStateService(nodePaths[0], nodeId, |
There was a problem hiding this comment.
We can fix nodePaths here too, indeed it's only used in this one method so can just be a local variable of type Path.
This reverts commit 2dfaf7a. The revert was not clean, it required merging with a few changes to loadOnDiskState since the initial removal of MDP support. relates elastic#71205
This commit removes multiple data path support from the
PersistedClusterStateService. Most notably, many error cases are no
longer possible where duplicate/conflicting data could previously exist
across multiple paths, there is now only one path.
relates #71205