Skip to content

Introduce project-global blocks #127978

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 13, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ static TransportVersion def(int id) {
public static final TransportVersion SEARCH_LOAD_PER_INDEX_STATS = def(9_095_0_00);
public static final TransportVersion HEAP_USAGE_IN_CLUSTER_INFO = def(9_096_0_00);
public static final TransportVersion NONE_CHUNKING_STRATEGY = def(9_097_0_00);
public static final TransportVersion PROJECT_DELETION_GLOBAL_BLOCK = def(9_098_0_00);

/*
* STOP! READ THIS FIRST! No, really,
Expand Down
45 changes: 33 additions & 12 deletions server/src/main/java/org/elasticsearch/cluster/ClusterState.java
Original file line number Diff line number Diff line change
Expand Up @@ -873,21 +873,24 @@ private Iterator<ToXContent> blocksXContentMultiProjects() {
}
builder.endObject();
}
if (blocks().noIndexBlockAllProjects() == false) {
if (blocks().noProjectHasAProjectBlock() == false) {
builder.startArray("projects");
}
return builder;
};
final ToXContent after = (builder, params) -> {
if (blocks().noIndexBlockAllProjects() == false) {
if (blocks().noProjectHasAProjectBlock() == false) {
builder.endArray();
}
return builder.endObject();
};
return chunkedSection(
true,
before,
Iterators.map(metadata().projects().keySet().iterator(), projectId -> new Tuple<>(projectId, blocks().indices(projectId))),
Iterators.map(
metadata().projects().keySet().iterator(),
projectId -> new Tuple<>(projectId, blocks().projectBlocks(projectId))
),
ClusterState::projectBlocksXContent,
after
);
Expand Down Expand Up @@ -929,19 +932,37 @@ private Iterator<ToXContent> blocksXContentSingleProject(ProjectId singleProject
);
}

private static Iterator<ToXContent> projectBlocksXContent(Tuple<ProjectId, Map<String, Set<ClusterBlock>>> entry) {
return chunkedSection(
entry.v2().isEmpty() == false,
(builder, params) -> builder.startObject().field("id", entry.v1()).startObject("indices"),
entry.v2().entrySet().iterator(),
e -> Iterators.single((builder, params) -> {
builder.startObject(e.getKey());
for (ClusterBlock block : e.getValue()) {
private static Iterator<ToXContent> projectBlocksXContent(Tuple<ProjectId, ClusterBlocks.ProjectBlocks> entry) {
final var projectId = entry.v1();
final var projectBlocks = entry.v2();
if (projectBlocks.isEmpty()) {
return Collections.emptyIterator();
}
return Iterators.concat(
Iterators.single((builder, params) -> builder.startObject().field("id", projectId)),
// write project global blocks in one chunk
projectBlocks.projectGlobals().isEmpty() ? Collections.emptyIterator() : Iterators.single((builder, params) -> {
builder.startObject("project_globals");
for (ClusterBlock block : projectBlocks.projectGlobals()) {
block.toXContent(builder, params);
}
return builder.endObject();
}),
(builder, params) -> builder.endObject().endObject()
// write index blocks for the project
projectBlocks.indices().isEmpty()
? Collections.emptyIterator()
: Iterators.concat(
Iterators.single((builder, params) -> builder.startObject("indices")),
Iterators.flatMap(projectBlocks.indices().entrySet().iterator(), indexBlocks -> Iterators.single((builder, params) -> {
builder.startObject(indexBlocks.getKey());
for (ClusterBlock block : indexBlocks.getValue()) {
block.toXContent(builder, params);
}
return builder.endObject();
})),
Iterators.single((builder, params) -> builder.endObject())
),
Iterators.single((builder, params) -> builder.endObject())
);
}

Expand Down
Loading