Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
aec37f7
Move per-project settings out of ProjectMetadata
alexey-ivanov-es Jun 6, 2025
83efe42
Update docs/changelog/129068.yaml
alexey-ivanov-es Jun 6, 2025
4be022c
Delete docs/changelog/129068.yaml
alexey-ivanov-es Jun 6, 2025
00f5e6f
[CI] Auto commit changes from spotless
Jun 6, 2025
bd1f9a2
Fix test
alexey-ivanov-es Jun 6, 2025
b930959
Fix tests
alexey-ivanov-es Jun 6, 2025
9a615a8
Fix test
alexey-ivanov-es Jun 6, 2025
a0ec70a
Merge branch 'main' into ES-11934
alexey-ivanov-es Jun 18, 2025
240d1a9
Move project settings to cluster state custom
alexey-ivanov-es Jun 18, 2025
ccd6fd5
[CI] Auto commit changes from spotless
Jun 18, 2025
756425e
Merge branch 'main' into ES-11934
alexey-ivanov-es Jun 18, 2025
194b110
Forgotten changes from the previous version
alexey-ivanov-es Jun 18, 2025
20e9296
[CI] Auto commit changes from spotless
Jun 18, 2025
4d83c70
Merge branch 'main' into ES-11934
alexey-ivanov-es Jun 19, 2025
4c3df9d
Fix tests
alexey-ivanov-es Jun 19, 2025
b4d31ab
Merge branch 'main' into ES-11934
alexey-ivanov-es Jun 19, 2025
572e063
[CI] Auto commit changes from spotless
Jun 19, 2025
6c4ce88
Merge branch 'main' into ES-11934
alexey-ivanov-es Jun 20, 2025
0955b5f
Address review comments
alexey-ivanov-es Jun 23, 2025
b292d36
Merge branch 'main' into ES-11934
alexey-ivanov-es Jun 23, 2025
b14cbf0
Merge remote-tracking branch 'refs/remotes/origin/ES-11934' into ES-1…
alexey-ivanov-es Jun 23, 2025
5dc56b2
[CI] Auto commit changes from spotless
Jun 23, 2025
c063093
Merge branch 'main' into ES-11934
alexey-ivanov-es Jun 24, 2025
c38cd42
Merge branch 'main' into ES-11934
alexey-ivanov-es Jun 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ static TransportVersion def(int id) {
public static final TransportVersion ILM_ADD_SKIP_SETTING = def(9_089_0_00);
public static final TransportVersion ML_INFERENCE_MISTRAL_CHAT_COMPLETION_ADDED = def(9_090_0_00);
public static final TransportVersion IDP_CUSTOM_SAML_ATTRIBUTES_ALLOW_LIST = def(9_091_0_00);
public static final TransportVersion CLUSTER_STATE_PROJECTS_SETTINGS = def(9_092_0_00);
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we actually need to introduce a new transport version here? The per-project stuff was never included in a stack release, and even in serverless it's behind the multi-project flag which isn't enabled in any production environment. I believe it's safe to remove this w/o introducing a new transport version.

Copy link
Contributor

Choose a reason for hiding this comment

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

@rjernst is my logic sound here?

Copy link
Member

@rjernst rjernst Jun 6, 2025

Choose a reason for hiding this comment

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

Maybe. I think the problem is when the feature flag is removed, a transport version would need to be introduced. Adding it here seems safer.


/*
* STOP! READ THIS FIRST! No, really,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ private ClusterStateResponse buildResponse(final ClusterStateRequest request, fi
ClusterState.Builder builder = ClusterState.builder(currentState.getClusterName());
builder.version(currentState.version());
builder.stateUUID(currentState.stateUUID());
builder.projectsSettings(currentState.projectsSettings());

if (request.nodes()) {
builder.nodes(currentState.nodes());
Expand Down
83 changes: 81 additions & 2 deletions server/src/main/java/org/elasticsearch/cluster/ClusterState.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.VersionedNamedWriteable;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.Maps;
import org.elasticsearch.common.xcontent.ChunkedToXContent;
import org.elasticsearch.common.xcontent.ChunkedToXContentHelper;
Expand Down Expand Up @@ -192,6 +193,8 @@ public CompatibilityVersions read(StreamInput in, String key) throws IOException

private final boolean wasReadFromDiff;

private final Map<ProjectId, Settings> projectsSettings;

// built on demand
private volatile RoutingNodes routingNodes;

Expand All @@ -208,6 +211,7 @@ public ClusterState(long version, String stateUUID, ClusterState state) {
state.blocks(),
state.customs(),
false,
state.projectsSettings,
state.routingNodes
);
}
Expand All @@ -224,6 +228,7 @@ public ClusterState(
ClusterBlocks blocks,
Map<String, Custom> customs,
boolean wasReadFromDiff,
Map<ProjectId, Settings> projectsSettings,
@Nullable RoutingNodes routingNodes
) {
this.version = version;
Expand All @@ -237,6 +242,7 @@ public ClusterState(
this.blocks = blocks;
this.customs = customs;
this.wasReadFromDiff = wasReadFromDiff;
this.projectsSettings = projectsSettings;
this.routingNodes = routingNodes;
assert assertConsistentRoutingNodes(routingTable, nodes, routingNodes);
assert assertConsistentProjectState(routingTable, metadata);
Expand Down Expand Up @@ -404,6 +410,14 @@ public RoutingTable routingTable(ProjectId projectId) {
return routingTable.routingTable(projectId);
}

public Settings projectSettings(ProjectId projectId) {
return projectsSettings.getOrDefault(projectId, Settings.EMPTY);
}

public Map<ProjectId, Settings> projectsSettings() {
return projectsSettings;
}

@Deprecated(forRemoval = true)
public RoutingTable routingTable() {
return routingTable.getRoutingTable();
Expand Down Expand Up @@ -672,7 +686,8 @@ public enum Metric {
METADATA("metadata"),
ROUTING_TABLE("routing_table"),
ROUTING_NODES("routing_nodes"),
CUSTOMS("customs");
CUSTOMS("customs"),
PROJECTS_SETTINGS("projects_settings");

private static final Map<String, Metric> valueToEnum;

Expand Down Expand Up @@ -849,7 +864,22 @@ public Iterator<? extends ToXContent> toXContentChunked(ToXContent.Params outerP
customs.entrySet().iterator(),
e -> ChunkedToXContentHelper.object(e.getKey(), e.getValue().toXContentChunked(outerParams))
)
: Collections.emptyIterator()
: Collections.emptyIterator(),

chunkedSection(
multiProject && metrics.contains(Metric.PROJECTS_SETTINGS),
(builder, params) -> builder.startArray("projects_settings"),
projectsSettings.entrySet().iterator(),

entry -> Iterators.single((builder, params) -> {
builder.startObject();
builder.field("id", entry.getKey());
builder.startObject("settings");
entry.getValue().toXContent(builder, new ToXContent.MapParams(Collections.singletonMap("flat_settings", "true")));
return builder.endObject().endObject();
}),
(builder, params) -> builder.endArray()
)
);
}

Expand Down Expand Up @@ -1006,6 +1036,7 @@ public static class Builder {
private final Map<String, Set<String>> nodeFeatures;
private ClusterBlocks blocks = ClusterBlocks.EMPTY_CLUSTER_BLOCK;
private final ImmutableOpenMap.Builder<String, Custom> customs;
private final ImmutableOpenMap.Builder<ProjectId, Settings> projectsSettings;
private boolean fromDiff;

public Builder(ClusterState state) {
Expand All @@ -1021,11 +1052,13 @@ public Builder(ClusterState state) {
this.blocks = state.blocks();
this.customs = ImmutableOpenMap.builder(state.customs());
this.fromDiff = false;
this.projectsSettings = ImmutableOpenMap.builder(state.projectsSettings);
}

public Builder(ClusterName clusterName) {
this.compatibilityVersions = new HashMap<>();
this.nodeFeatures = new HashMap<>();
this.projectsSettings = ImmutableOpenMap.builder();
customs = ImmutableOpenMap.builder();
this.clusterName = clusterName;
}
Expand Down Expand Up @@ -1130,6 +1163,16 @@ public Builder putRoutingTable(ProjectId projectId, RoutingTable routingTable) {
return routingTable(globalRoutingTableBuilder.put(projectId, routingTable).build());
}

public Builder putProjectSettings(ProjectId projectId, Settings settings) {
projectsSettings.put(projectId, settings);
return this;
}

public Builder projectsSettings(Map<ProjectId, Settings> projectsSettings) {
this.projectsSettings.putAllFromMap(projectsSettings);
return this;
}

public Builder metadata(Metadata.Builder metadataBuilder) {
return metadata(metadataBuilder.build());
}
Expand Down Expand Up @@ -1234,6 +1277,7 @@ public ClusterState build() {
metadata != null ? blocks.initializeProjects(metadata.projects().keySet()) : blocks,
customs.build(),
fromDiff,
projectsSettings.build(),
routingNodes
);
}
Expand Down Expand Up @@ -1285,6 +1329,9 @@ public static ClusterState readFrom(StreamInput in, DiscoveryNode localNode) thr
Custom customIndexMetadata = in.readNamedWriteable(Custom.class);
builder.putCustom(customIndexMetadata.getWriteableName(), customIndexMetadata);
}
if (in.getTransportVersion().onOrAfter(TransportVersions.CLUSTER_STATE_PROJECTS_SETTINGS)) {
builder.projectsSettings(in.readMap(ProjectId::readFrom, Settings::readSettingsFromStream));
}
return builder.build();
}

Expand All @@ -1306,9 +1353,24 @@ public void writeTo(StreamOutput out) throws IOException {
clusterFeatures.writeTo(out);
blocks.writeTo(out);
VersionedNamedWriteable.writeVersionedWritables(out, customs);
if (out.getTransportVersion().onOrAfter(TransportVersions.CLUSTER_STATE_PROJECTS_SETTINGS)) {
out.writeMap(projectsSettings);
}
}

private static class ClusterStateDiff implements Diff<ClusterState> {
private static final DiffableUtils.ValueSerializer<ProjectId, Settings> SETTINGS_SERIALIZER =
new DiffableUtils.DiffableValueSerializer<>() {
@Override
public Settings read(StreamInput in, ProjectId key) throws IOException {
return Settings.readSettingsFromStream(in);
}

@Override
public Diff<Settings> readDiff(StreamInput in, ProjectId key) throws IOException {
return Settings.readSettingsDiffFromStream(in);
}
};

private final long toVersion;

Expand All @@ -1331,6 +1393,8 @@ private static class ClusterStateDiff implements Diff<ClusterState> {

private final Diff<Map<String, Custom>> customs;

private final DiffableUtils.MapDiff<ProjectId, Settings, Map<ProjectId, Settings>> projectsSettings;

ClusterStateDiff(ClusterState before, ClusterState after) {
fromUuid = before.stateUUID;
toUuid = after.stateUUID;
Expand All @@ -1348,6 +1412,12 @@ private static class ClusterStateDiff implements Diff<ClusterState> {
metadata = after.metadata.diff(before.metadata);
blocks = after.blocks.diff(before.blocks);
customs = DiffableUtils.diff(before.customs, after.customs, DiffableUtils.getStringKeySerializer(), CUSTOM_VALUE_SERIALIZER);
projectsSettings = DiffableUtils.diff(
before.projectsSettings,
after.projectsSettings,
ProjectId.PROJECT_ID_SERIALIZER,
SETTINGS_SERIALIZER
);
}

ClusterStateDiff(StreamInput in, DiscoveryNode localNode) throws IOException {
Expand All @@ -1364,6 +1434,11 @@ private static class ClusterStateDiff implements Diff<ClusterState> {
metadata = Metadata.readDiffFrom(in);
blocks = ClusterBlocks.readDiffFrom(in);
customs = DiffableUtils.readJdkMapDiff(in, DiffableUtils.getStringKeySerializer(), CUSTOM_VALUE_SERIALIZER);
if (in.getTransportVersion().onOrAfter(TransportVersions.CLUSTER_STATE_PROJECTS_SETTINGS)) {
projectsSettings = DiffableUtils.readJdkMapDiff(in, ProjectId.PROJECT_ID_SERIALIZER, SETTINGS_SERIALIZER);
} else {
projectsSettings = DiffableUtils.emptyDiff();
}
}

@Override
Expand All @@ -1380,6 +1455,9 @@ public void writeTo(StreamOutput out) throws IOException {
metadata.writeTo(out);
blocks.writeTo(out);
customs.writeTo(out);
if (out.getTransportVersion().onOrAfter(TransportVersions.CLUSTER_STATE_PROJECTS_SETTINGS)) {
projectsSettings.writeTo(out);
}
}

@Override
Expand All @@ -1401,6 +1479,7 @@ public ClusterState apply(ClusterState state) {
builder.metadata(metadata.apply(state.metadata));
builder.blocks(blocks.apply(state.blocks));
builder.customs(customs.apply(state.customs));
builder.projectsSettings(this.projectsSettings.apply(state.projectsSettings));
builder.fromDiff(state);
return builder.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.elasticsearch.cluster.metadata.ProjectMetadata;
import org.elasticsearch.cluster.routing.RoutingTable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;

import java.util.Objects;
import java.util.function.Consumer;
Expand All @@ -26,6 +27,7 @@ public final class ProjectState {
private final ClusterState cluster;
private final ProjectId project;
private final ProjectMetadata projectMetadata;
private final Settings projectSettings;
private final RoutingTable routingTable;

ProjectState(ClusterState clusterState, ProjectId projectId) {
Expand All @@ -34,6 +36,7 @@ public final class ProjectState {
this.cluster = clusterState;
this.project = projectId;
this.projectMetadata = clusterState.metadata().getProject(projectId);
this.projectSettings = clusterState.projectSettings(projectId);
this.routingTable = clusterState.routingTable(projectId);
}

Expand All @@ -57,6 +60,10 @@ public ClusterBlocks blocks() {
return cluster().blocks();
}

public Settings settings() {
return projectSettings;
}

@Override
public boolean equals(Object obj) {
if (obj == this) return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -801,10 +801,6 @@ private Iterator<? extends ToXContent> toXContentChunkedWithSingleProjectFormat(
);
}

private static final DiffableUtils.KeySerializer<ProjectId> PROJECT_ID_SERIALIZER = DiffableUtils.getWriteableKeySerializer(
ProjectId.READER
);

private static class MetadataDiff implements Diff<Metadata> {

private final long version;
Expand Down Expand Up @@ -846,7 +842,7 @@ private static class MetadataDiff implements Diff<Metadata> {
multiProject = null;
} else {
singleProject = null;
multiProject = DiffableUtils.diff(before.projectMetadata, after.projectMetadata, PROJECT_ID_SERIALIZER);
multiProject = DiffableUtils.diff(before.projectMetadata, after.projectMetadata, ProjectId.PROJECT_ID_SERIALIZER);
}

if (empty) {
Expand Down Expand Up @@ -951,13 +947,7 @@ private MetadataDiff(StreamInput in) throws IOException {
RESERVED_DIFF_VALUE_READER
);

singleProject = new ProjectMetadata.ProjectMetadataDiff(
indices,
templates,
projectCustoms,
DiffableUtils.emptyDiff(),
Settings.EMPTY_DIFF
);
singleProject = new ProjectMetadata.ProjectMetadataDiff(indices, templates, projectCustoms, DiffableUtils.emptyDiff());
multiProject = null;
} else {
fromNodeBeforeMultiProjectsSupport = false;
Expand Down Expand Up @@ -1001,7 +991,7 @@ private static MapDiff<ProjectId, ProjectMetadata, Map<ProjectId, ProjectMetadat
) throws IOException {
final var multiProject = DiffableUtils.readJdkMapDiff(
in,
PROJECT_ID_SERIALIZER,
ProjectId.PROJECT_ID_SERIALIZER,
ProjectMetadata::readFrom,
ProjectMetadata.ProjectMetadataDiff::new
);
Expand Down Expand Up @@ -1075,7 +1065,7 @@ public void writeTo(StreamOutput out) throws IOException {
} else {
final var multiProjectToWrite = multiProject != null
? multiProject
: DiffableUtils.singleEntryDiff(DEFAULT_PROJECT_ID, singleProject, PROJECT_ID_SERIALIZER);
: DiffableUtils.singleEntryDiff(DEFAULT_PROJECT_ID, singleProject, ProjectId.PROJECT_ID_SERIALIZER);

if (out.getTransportVersion().before(TransportVersions.REPOSITORIES_METADATA_AS_PROJECT_CUSTOM)) {
writeDiffWithRepositoriesMetadataAsClusterCustom(out, clusterCustoms, multiProjectToWrite, reservedStateMetadata);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

package org.elasticsearch.cluster.metadata;

import org.elasticsearch.cluster.DiffableUtils;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
Expand All @@ -26,6 +27,9 @@ public class ProjectId implements Writeable, ToXContent {
private static final String DEFAULT_STRING = "default";
public static final ProjectId DEFAULT = new ProjectId(DEFAULT_STRING);
public static final Reader<ProjectId> READER = ProjectId::readFrom;
public static final DiffableUtils.KeySerializer<ProjectId> PROJECT_ID_SERIALIZER = DiffableUtils.getWriteableKeySerializer(
ProjectId.READER
);
private static final int MAX_LENGTH = 128;

private final String id;
Expand Down
Loading