Skip to content

Remove MDP from PersistedClusterStateService#72278

Merged
rjernst merged 12 commits intoelastic:masterfrom
rjernst:mdp10
May 5, 2021
Merged

Remove MDP from PersistedClusterStateService#72278
rjernst merged 12 commits intoelastic:masterfrom
rjernst:mdp10

Conversation

@rjernst
Copy link
Copy Markdown
Member

@rjernst rjernst commented Apr 26, 2021

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

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
@rjernst rjernst added :Core/Infra/Core Core issues without another label >refactoring v8.0.0 labels Apr 26, 2021
@elasticmachine elasticmachine added the Team:Core/Infra Meta label for core/infra team label Apr 26, 2021
@elasticmachine
Copy link
Copy Markdown
Collaborator

Pinging @elastic/es-core-infra (Team:Core/Infra)

@rjernst
Copy link
Copy Markdown
Member Author

rjernst commented Apr 26, 2021

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.

Copy link
Copy Markdown
Member

@DaveCTurner DaveCTurner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is still meaningful, although we'll need to work out a more creative way to duplicate that document.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is still meaningful, although we'll need to work out a more creative way to duplicate that document.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)));
        }
    }

rjernst added 8 commits April 27, 2021 08:31
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
@rjernst
Copy link
Copy Markdown
Member Author

rjernst commented May 4, 2021

Thanks for laying out the modified tests @DaveCTurner. I've added them back as suggested. I think this PR is ready for review again.

Copy link
Copy Markdown
Member

@DaveCTurner DaveCTurner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@rjernst rjernst merged commit 2dfaf7a into elastic:master May 5, 2021
@rjernst rjernst deleted the mdp10 branch May 5, 2021 18:51
rjernst added a commit to rjernst/elasticsearch that referenced this pull request Sep 30, 2021
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
@rjernst rjernst mentioned this pull request Sep 30, 2021
17 tasks
rjernst added a commit that referenced this pull request Oct 4, 2021
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 #71205
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

:Core/Infra/Core Core issues without another label >refactoring Team:Core/Infra Meta label for core/infra team v8.0.0-alpha1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants