Skip to content

Commit 371021a

Browse files
alexey-ivanov-esJeremyDahlgren
authored andcommitted
Projects reserved state is moved to ProjectStateRegistry (elastic#132332)
This commit refactors how project reserved state is stored and accessed in Elasticsearch. Instead of storing reserved state metadata directly within each ProjectMetadata object, the commit moves it to a centralized ProjectStateRegistry. Note: In mixed-version multiproject clusters, this may cause existing reserved state metadata for projects to temporarily disappear until all nodes have been upgraded and restarted. It also maintains the logic for resetting reserved state metadata during snapshot restore, ensuring that the reserved state will be reread and re-applied to the cluster state.
1 parent 13c37e0 commit 371021a

21 files changed

+279
-169
lines changed

server/src/main/java/org/elasticsearch/TransportVersions.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ static TransportVersion def(int id) {
357357
public static final TransportVersion ESQL_SAMPLE_OPERATOR_STATUS = def(9_127_0_00);
358358
public static final TransportVersion ALLOCATION_DECISION_NOT_PREFERRED = def(9_145_0_00);
359359
public static final TransportVersion ESQL_QUALIFIERS_IN_ATTRIBUTES = def(9_146_0_00);
360+
public static final TransportVersion PROJECT_RESERVED_STATE_MOVE_TO_REGISTRY = def(9_147_0_00);
360361

361362
/*
362363
* STOP! READ THIS FIRST! No, really,

server/src/main/java/org/elasticsearch/action/admin/cluster/repositories/delete/TransportDeleteRepositoryAction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.elasticsearch.cluster.block.ClusterBlockException;
2020
import org.elasticsearch.cluster.block.ClusterBlockLevel;
2121
import org.elasticsearch.cluster.project.ProjectResolver;
22+
import org.elasticsearch.cluster.project.ProjectStateRegistry;
2223
import org.elasticsearch.cluster.service.ClusterService;
2324
import org.elasticsearch.common.util.concurrent.EsExecutors;
2425
import org.elasticsearch.injection.guice.Inject;
@@ -91,7 +92,7 @@ protected void validateForReservedState(DeleteRepositoryRequest request, Cluster
9192
super.validateForReservedState(request, state);
9293

9394
validateForReservedState(
94-
projectResolver.getProjectMetadata(state).reservedStateMetadata().values(),
95+
ProjectStateRegistry.get(state).reservedStateMetadata(projectResolver.getProjectId()).values(),
9596
reservedStateHandlerName().get(),
9697
modifiedKeys(request),
9798
request.toString()

server/src/main/java/org/elasticsearch/action/admin/indices/template/delete/TransportDeleteComposableIndexTemplateAction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.elasticsearch.cluster.block.ClusterBlockLevel;
2323
import org.elasticsearch.cluster.metadata.MetadataIndexTemplateService;
2424
import org.elasticsearch.cluster.project.ProjectResolver;
25+
import org.elasticsearch.cluster.project.ProjectStateRegistry;
2526
import org.elasticsearch.cluster.service.ClusterService;
2627
import org.elasticsearch.common.Strings;
2728
import org.elasticsearch.common.io.stream.StreamInput;
@@ -95,7 +96,7 @@ protected void validateForReservedState(Request request, ClusterState state) {
9596
super.validateForReservedState(request, state);
9697

9798
validateForReservedState(
98-
projectResolver.getProjectMetadata(state).reservedStateMetadata().values(),
99+
ProjectStateRegistry.get(state).reservedStateMetadata(projectResolver.getProjectId()).values(),
99100
reservedStateHandlerName().get(),
100101
modifiedKeys(request),
101102
request.toString()

server/src/main/java/org/elasticsearch/action/admin/indices/template/put/TransportPutComponentTemplateAction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.elasticsearch.cluster.metadata.MetadataIndexTemplateService;
2323
import org.elasticsearch.cluster.metadata.Template;
2424
import org.elasticsearch.cluster.project.ProjectResolver;
25+
import org.elasticsearch.cluster.project.ProjectStateRegistry;
2526
import org.elasticsearch.cluster.service.ClusterService;
2627
import org.elasticsearch.common.settings.IndexScopedSettings;
2728
import org.elasticsearch.common.settings.Settings;
@@ -130,7 +131,7 @@ protected void validateForReservedState(PutComponentTemplateAction.Request reque
130131
super.validateForReservedState(request, state);
131132

132133
validateForReservedState(
133-
projectResolver.getProjectMetadata(state).reservedStateMetadata().values(),
134+
ProjectStateRegistry.get(state).reservedStateMetadata(projectResolver.getProjectId()).values(),
134135
reservedStateHandlerName().get(),
135136
modifiedKeys(request),
136137
request.toString()

server/src/main/java/org/elasticsearch/action/admin/indices/template/put/TransportPutComposableIndexTemplateAction.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.elasticsearch.cluster.metadata.ProjectId;
2929
import org.elasticsearch.cluster.metadata.ReservedStateMetadata;
3030
import org.elasticsearch.cluster.project.ProjectResolver;
31+
import org.elasticsearch.cluster.project.ProjectStateRegistry;
3132
import org.elasticsearch.cluster.service.ClusterService;
3233
import org.elasticsearch.common.Strings;
3334
import org.elasticsearch.common.io.stream.StreamInput;
@@ -87,7 +88,10 @@ protected void masterOperation(
8788
) {
8889
ProjectId projectId = projectResolver.getProjectId();
8990
verifyIfUsingReservedComponentTemplates(request, state.metadata().reservedStateMetadata().values());
90-
verifyIfUsingReservedComponentTemplates(request, state.metadata().getProject(projectId).reservedStateMetadata().values());
91+
verifyIfUsingReservedComponentTemplates(
92+
request,
93+
ProjectStateRegistry.get(state).reservedStateMetadata(projectResolver.getProjectId()).values()
94+
);
9195
ComposableIndexTemplate indexTemplate = request.indexTemplate();
9296
indexTemplateService.putIndexTemplateV2(
9397
request.cause(),
@@ -138,7 +142,7 @@ protected void validateForReservedState(Request request, ClusterState state) {
138142
super.validateForReservedState(request, state);
139143

140144
validateForReservedState(
141-
projectResolver.getProjectMetadata(state).reservedStateMetadata().values(),
145+
ProjectStateRegistry.get(state).reservedStateMetadata(projectResolver.getProjectId()).values(),
142146
reservedStateHandlerName().get(),
143147
modifiedKeys(request),
144148
request.toString()

server/src/main/java/org/elasticsearch/action/ingest/PutPipelineTransportAction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.elasticsearch.cluster.block.ClusterBlockException;
1919
import org.elasticsearch.cluster.block.ClusterBlockLevel;
2020
import org.elasticsearch.cluster.project.ProjectResolver;
21+
import org.elasticsearch.cluster.project.ProjectStateRegistry;
2122
import org.elasticsearch.common.util.concurrent.EsExecutors;
2223
import org.elasticsearch.ingest.IngestService;
2324
import org.elasticsearch.injection.guice.Inject;
@@ -80,7 +81,7 @@ protected void validateForReservedState(PutPipelineRequest request, ClusterState
8081
super.validateForReservedState(request, state);
8182

8283
validateForReservedState(
83-
projectResolver.getProjectMetadata(state).reservedStateMetadata().values(),
84+
ProjectStateRegistry.get(state).reservedStateMetadata(projectResolver.getProjectId()).values(),
8485
reservedStateHandlerName().get(),
8586
modifiedKeys(request),
8687
request.toString()

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

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
import java.util.Objects;
6262
import java.util.Optional;
6363
import java.util.Set;
64-
import java.util.TreeMap;
6564
import java.util.function.BiConsumer;
6665
import java.util.function.BiPredicate;
6766
import java.util.function.Consumer;
@@ -799,12 +798,6 @@ private Iterator<? extends ToXContent> toXContentChunkedWithSingleProjectFormat(
799798
@FixForMultiProject
800799
final ProjectMetadata project = projectMetadata.values().iterator().next();
801800

802-
// need to combine reserved state together into a single block so we don't get duplicate keys
803-
// and not include it in the project xcontent output (through the lack of multi-project params)
804-
// use a tree map so the order is deterministic
805-
final Map<String, ReservedStateMetadata> clusterReservedState = new TreeMap<>(reservedStateMetadata);
806-
clusterReservedState.putAll(project.reservedStateMetadata());
807-
808801
// Similarly, combine cluster and project persistent tasks and report them under a single key
809802
Iterator<ToXContent> customs = Iterators.flatMap(customs().entrySet().iterator(), entry -> {
810803
if (entry.getValue().context().contains(context) && ClusterPersistentTasksCustomMetadata.TYPE.equals(entry.getKey()) == false) {
@@ -824,13 +817,20 @@ private Iterator<? extends ToXContent> toXContentChunkedWithSingleProjectFormat(
824817
);
825818
}
826819

820+
// make order deterministic
821+
Iterator<ReservedStateMetadata> reservedStateMetadataIterator = reservedStateMetadata.entrySet()
822+
.stream()
823+
.sorted(Map.Entry.comparingByKey())
824+
.map(Map.Entry::getValue)
825+
.iterator();
826+
827827
return Iterators.concat(
828828
start,
829829
clusterCoordination,
830830
persistentSettings,
831831
project.toXContentChunked(p),
832832
customs,
833-
ChunkedToXContentHelper.object("reserved_state", clusterReservedState.values().iterator()),
833+
ChunkedToXContentHelper.object("reserved_state", reservedStateMetadataIterator),
834834
ChunkedToXContentHelper.endObject()
835835
);
836836
}
@@ -845,6 +845,7 @@ private static class MetadataDiff implements Diff<Metadata> {
845845
private final Settings persistentSettings;
846846
private final Diff<DiffableStringMap> hashesOfConsistentSettings;
847847
private final ProjectMetadata.ProjectMetadataDiff singleProject;
848+
848849
private final MapDiff<ProjectId, ProjectMetadata, Map<ProjectId, ProjectMetadata>> multiProject;
849850
private final MapDiff<String, ClusterCustom, ImmutableOpenMap<String, ClusterCustom>> clusterCustoms;
850851
private final MapDiff<String, ReservedStateMetadata, ImmutableOpenMap<String, ReservedStateMetadata>> reservedStateMetadata;
@@ -981,7 +982,7 @@ private MetadataDiff(StreamInput in) throws IOException {
981982
RESERVED_DIFF_VALUE_READER
982983
);
983984

984-
singleProject = new ProjectMetadata.ProjectMetadataDiff(indices, templates, projectCustoms, DiffableUtils.emptyDiff());
985+
singleProject = new ProjectMetadata.ProjectMetadataDiff(indices, templates, projectCustoms);
985986
multiProject = null;
986987
} else {
987988
fromNodeBeforeMultiProjectsSupport = false;
@@ -1048,7 +1049,7 @@ public void writeTo(StreamOutput out) throws IOException {
10481049
singleProject.indices().writeTo(out);
10491050
singleProject.templates().writeTo(out);
10501051
buildUnifiedCustomDiff().writeTo(out);
1051-
buildUnifiedReservedStateMetadataDiff().writeTo(out);
1052+
reservedStateMetadata.writeTo(out);
10521053
} else {
10531054
clusterCustoms.writeTo(out);
10541055
reservedStateMetadata.writeTo(out);
@@ -1094,15 +1095,6 @@ public void writeTo(StreamOutput out) throws IOException {
10941095
}
10951096
}
10961097

1097-
private Diff<Map<String, ReservedStateMetadata>> buildUnifiedReservedStateMetadataDiff() {
1098-
return DiffableUtils.merge(
1099-
reservedStateMetadata,
1100-
singleProject.reservedStateMetadata(),
1101-
DiffableUtils.getStringKeySerializer(),
1102-
RESERVED_DIFF_VALUE_READER
1103-
);
1104-
}
1105-
11061098
@Override
11071099
public Metadata apply(Metadata part) {
11081100
if (empty) {
@@ -1304,12 +1296,7 @@ public void writeTo(StreamOutput out) throws IOException {
13041296
);
13051297
VersionedNamedWriteable.writeVersionedWriteables(out, combinedCustoms);
13061298

1307-
List<ReservedStateMetadata> combinedMetadata = new ArrayList<>(
1308-
reservedStateMetadata.size() + singleProject.reservedStateMetadata().size()
1309-
);
1310-
combinedMetadata.addAll(reservedStateMetadata.values());
1311-
combinedMetadata.addAll(singleProject.reservedStateMetadata().values());
1312-
out.writeCollection(combinedMetadata);
1299+
out.writeCollection(reservedStateMetadata.values());
13131300
} else {
13141301
VersionedNamedWriteable.writeVersionedWriteables(out, customs.values());
13151302

0 commit comments

Comments
 (0)