Skip to content

Commit 6b53351

Browse files
authored
Skip data stream reference check in some cases (#135457)
During component and composable template validation we check if any data streams become unreferenced if the composite template would be added to the project metadata. We currently do this regardless of what changed in the component or composable template. This check is quite expensive if the cluster has many index templates or many data streams, mostly because the regex matching on index patterns in `findV2Template` is expensive. We know that only a few properties of the composite template can affect data stream references. Specifically, we know that the index patterns, the `hidden` index setting, the priority, and the presence of the `data_stream` field in the template are used to determine the template that a data stream is based on. By checking if only one of those properties changed, we can avoid running the expensive checks in a great deal of template updates. For example, mapping updates, `_meta` updates, any index settings other than `hidden` are all irrelevant to this check, and we can thus skip it for those updates. Especially component template updates will benefit from this change, as they aren't even able to influence the index patterns, data stream template, or priority of the composite template. The main downside of this change is that we have an implicit dependency from this new check on the implementation of `findV2Template`. We try to mitigate that risk by doing the expensive/original check in an assertion.
1 parent dc6ac5e commit 6b53351

File tree

1 file changed

+45
-9
lines changed

1 file changed

+45
-9
lines changed

server/src/main/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateService.java

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.elasticsearch.common.settings.IndexScopedSettings;
3535
import org.elasticsearch.common.settings.Settings;
3636
import org.elasticsearch.common.util.set.Sets;
37+
import org.elasticsearch.core.Assertions;
3738
import org.elasticsearch.core.Nullable;
3839
import org.elasticsearch.core.TimeValue;
3940
import org.elasticsearch.core.Tuple;
@@ -818,7 +819,7 @@ void validateIndexTemplateV2(ProjectMetadata projectMetadata, String name, Compo
818819
var templateToValidate = indexTemplate.toBuilder().template(Template.builder(finalTemplate).settings(finalSettings)).build();
819820

820821
validate(name, templateToValidate, additionalSettings);
821-
validateDataStreamsStillReferenced(projectMetadata, name, templateToValidate);
822+
maybeValidateDataStreamsStillReferenced(projectMetadata, name, templateToValidate);
822823
validateLifecycle(componentTemplates, name, templateToValidate, globalRetentionSettings.get(false));
823824
validateDataStreamOptions(componentTemplates, name, templateToValidate, globalRetentionSettings.get(true));
824825

@@ -944,6 +945,43 @@ static void validateDataStreamOptions(
944945
}
945946
}
946947

948+
/**
949+
* Maybe runs {@link #validateDataStreamsStillReferenced} if it looks like the new composite template could change data stream coverage.
950+
*/
951+
private static void maybeValidateDataStreamsStillReferenced(
952+
ProjectMetadata project,
953+
String templateName,
954+
ComposableIndexTemplate newTemplate
955+
) {
956+
final ComposableIndexTemplate existingTemplate = project.templatesV2().get(templateName);
957+
final Settings existingSettings = Optional.ofNullable(existingTemplate)
958+
.map(ComposableIndexTemplate::template)
959+
.map(Template::settings)
960+
.orElse(Settings.EMPTY);
961+
final Settings newSettings = Optional.ofNullable(newTemplate)
962+
.map(ComposableIndexTemplate::template)
963+
.map(Template::settings)
964+
.orElse(Settings.EMPTY);
965+
// We check whether anything relevant has changed that could affect data stream coverage and return early if not.
966+
// These checks are based on the implementation of findV2Template and the data stream template check in this method.
967+
// If we're adding a new template, we do the full check in case this template's priority changes coverage.
968+
if (existingTemplate != null
969+
&& Objects.equals(existingTemplate.indexPatterns(), newTemplate.indexPatterns())
970+
&& Objects.equals(existingSettings.get(IndexMetadata.SETTING_INDEX_HIDDEN), newSettings.get(IndexMetadata.SETTING_INDEX_HIDDEN))
971+
&& Objects.equals(existingTemplate.getDataStreamTemplate() != null, newTemplate.getDataStreamTemplate() != null)
972+
&& Objects.equals(existingTemplate.priorityOrZero(), newTemplate.priorityOrZero())) {
973+
if (Assertions.ENABLED) {
974+
try {
975+
validateDataStreamsStillReferenced(project, templateName, newTemplate);
976+
} catch (IllegalArgumentException e) {
977+
assert false : "Data stream reference validation took a shortcut but the full check failed: " + e.getMessage();
978+
}
979+
}
980+
return;
981+
}
982+
validateDataStreamsStillReferenced(project, templateName, newTemplate);
983+
}
984+
947985
/**
948986
* Validate that by changing or adding {@code newTemplate}, there are
949987
* no unreferenced data streams. Note that this scenario is still possible
@@ -955,18 +993,16 @@ private static void validateDataStreamsStillReferenced(
955993
String templateName,
956994
ComposableIndexTemplate newTemplate
957995
) {
958-
final Set<String> dataStreams = project.dataStreams()
959-
.entrySet()
960-
.stream()
961-
.filter(entry -> entry.getValue().isSystem() == false)
962-
.map(Map.Entry::getKey)
963-
.collect(Collectors.toSet());
964-
965996
Function<Map<String, ComposableIndexTemplate>, Set<String>> findUnreferencedDataStreams = composableTemplates -> {
966997
final Set<String> unreferenced = new HashSet<>();
967998
// For each data stream that we have, see whether it's covered by a different
968999
// template (which is great), or whether it's now uncovered by any template
969-
for (String dataStream : dataStreams) {
1000+
for (var dataStreamEntry : project.dataStreams().entrySet()) {
1001+
// Exclude system data streams
1002+
if (dataStreamEntry.getValue().isSystem()) {
1003+
continue;
1004+
}
1005+
final String dataStream = dataStreamEntry.getKey();
9701006
final String matchingTemplate = findV2Template(project, composableTemplates.entrySet(), dataStream, false, false);
9711007
if (matchingTemplate == null) {
9721008
unreferenced.add(dataStream);

0 commit comments

Comments
 (0)