1717import org .elasticsearch .cluster .metadata .Metadata ;
1818import org .elasticsearch .cluster .metadata .MetadataIndexStateService ;
1919import org .elasticsearch .cluster .metadata .ProjectId ;
20+ import org .elasticsearch .cluster .metadata .ProjectMetadata ;
2021import org .elasticsearch .common .io .stream .StreamInput ;
2122import org .elasticsearch .common .io .stream .StreamOutput ;
2223import org .elasticsearch .common .io .stream .Writeable ;
4344public class ClusterBlocks implements Diffable <ClusterBlocks > {
4445 private static final ClusterBlock [] EMPTY_BLOCKS_ARRAY = new ClusterBlock [0 ];
4546
46- public static final ClusterBlocks EMPTY_CLUSTER_BLOCK = new ClusterBlocks (Set .of (), Map .of ());
47+ public static final ClusterBlocks EMPTY_CLUSTER_BLOCK = new ClusterBlocks (Set .of (), Map .of (), 0 );
4748
4849 private final Set <ClusterBlock > global ;
4950
@@ -57,15 +58,17 @@ public class ClusterBlocks implements Diffable<ClusterBlocks> {
5758 */
5859 // Package private for testing
5960 final Map <ProjectId , ProjectBlocks > projectBlocksMap ;
61+ private final long projectsWithUnderDeletionBlockGeneration ;
6062
6163 private final EnumMap <ClusterBlockLevel , ImmutableLevelHolder > levelHolders ;
6264
63- ClusterBlocks (Set <ClusterBlock > global , Map <ProjectId , ProjectBlocks > projectBlocksMap ) {
65+ ClusterBlocks (Set <ClusterBlock > global , Map <ProjectId , ProjectBlocks > projectBlocksMap , long projectsWithUnderDeletionBlockGeneration ) {
6466 this .global = global ;
6567 assert projectBlocksMap .values ().stream ().allMatch (projectBlocks -> projectBlocks .isEmpty () == false )
6668 : "Map must not contain projects with empty blocks " + projectBlocksMap ;
6769 this .projectBlocksMap = projectBlocksMap ;
6870 this .levelHolders = generateLevelHolders (global , projectBlocksMap );
71+ this .projectsWithUnderDeletionBlockGeneration = projectsWithUnderDeletionBlockGeneration ;
6972 }
7073
7174 public Set <ClusterBlock > global () {
@@ -165,6 +168,14 @@ public boolean hasGlobalBlock(ClusterBlock block) {
165168 return global .contains (block );
166169 }
167170
171+ public boolean hasProjectGlobalBlock (ProjectId projectId , ClusterBlock block ) {
172+ var projectBlocks = projectBlocksMap .get (projectId );
173+ if (projectBlocks == null ) {
174+ return false ;
175+ }
176+ return projectBlocks .projectGlobals ().contains (block );
177+ }
178+
168179 public boolean hasGlobalBlockWithId (final int blockId ) {
169180 for (ClusterBlock clusterBlock : global ) {
170181 if (clusterBlock .id () == blockId ) {
@@ -493,7 +504,7 @@ && noProjectOrDefaultProjectOnly(projectBlocksMap)
493504 && projectBlocksMap .getOrDefault (Metadata .DEFAULT_PROJECT_ID , ProjectBlocks .EMPTY ).indices ().isEmpty ()) {
494505 return EMPTY_CLUSTER_BLOCK ;
495506 }
496- return new ClusterBlocks (global , projectBlocksMap );
507+ return new ClusterBlocks (global , projectBlocksMap , 0 /*todo*/ );
497508 } else {
498509 return readFromSingleProjectNode (in );
499510 }
@@ -506,9 +517,9 @@ private static ClusterBlocks readFromSingleProjectNode(StreamInput in) throws IO
506517 return EMPTY_CLUSTER_BLOCK ;
507518 }
508519 if (indicesBlocks .isEmpty ()) {
509- return new ClusterBlocks (global , Map .of ());
520+ return new ClusterBlocks (global , Map .of (), 0 );
510521 }
511- return new ClusterBlocks (global , Map .of (Metadata .DEFAULT_PROJECT_ID , new ProjectBlocks (indicesBlocks , Set .of ())));
522+ return new ClusterBlocks (global , Map .of (Metadata .DEFAULT_PROJECT_ID , new ProjectBlocks (indicesBlocks , Set .of ())), 0 );
512523 }
513524
514525 private static Set <ClusterBlock > readBlockSet (StreamInput in ) throws IOException {
@@ -602,6 +613,10 @@ public ClusterBlocks initializeProjects(Set<ProjectId> projectIds) {
602613 }
603614 }
604615
616+ public long projectsWithUnderDeletionBlockGeneration () {
617+ return projectsWithUnderDeletionBlockGeneration ;
618+ }
619+
605620 public static Builder builder () {
606621 return new Builder ();
607622 }
@@ -617,6 +632,8 @@ public static class Builder {
617632
618633 private final Set <ClusterBlock > global = new HashSet <>();
619634 private final Map <ProjectId , ProjectBlocks > projects = new HashMap <>();
635+ private long projectsWithUnderDeletionBlockGeneration = 0 ;
636+ private boolean newProjectsWithUnderDeletionBlock = false ;
620637
621638 public Builder () {}
622639
@@ -636,6 +653,7 @@ public Builder blocks(ClusterBlocks blocks) {
636653 projectBlocks .indices .get (entry .getKey ()).addAll (entry .getValue ());
637654 }
638655 }
656+ this .projectsWithUnderDeletionBlockGeneration = blocks .projectsWithUnderDeletionBlockGeneration ();
639657 return this ;
640658 }
641659
@@ -700,7 +718,10 @@ public Builder removeProject(ProjectId projectId) {
700718
701719 public Builder addProjectGlobalBlock (ProjectId projectId , ClusterBlock block ) {
702720 assert projectId .equals (ProjectId .DEFAULT ) == false ;
703- projects .computeIfAbsent (projectId , k -> emptyMutableProjectBlocks ()).projectGlobal .add (block );
721+ boolean added = projects .computeIfAbsent (projectId , k -> emptyMutableProjectBlocks ()).projectGlobal .add (block );
722+ if (newProjectsWithUnderDeletionBlock == false && block .id () == ProjectMetadata .PROJECT_UNDER_DELETION_BLOCK .id () && added ) {
723+ newProjectsWithUnderDeletionBlock = true ;
724+ }
704725 return this ;
705726 }
706727
@@ -812,7 +833,10 @@ && noProjectOrDefaultProjectOnly(projects)
812833 );
813834 }
814835 }
815- return new ClusterBlocks (Set .copyOf (global ), Map .copyOf (projectsBuilder ));
836+ long newProjectsWithUnderDeletionBlockGeneration = newProjectsWithUnderDeletionBlock
837+ ? projectsWithUnderDeletionBlockGeneration + 1
838+ : projectsWithUnderDeletionBlockGeneration ;
839+ return new ClusterBlocks (Set .copyOf (global ), Map .copyOf (projectsBuilder ), newProjectsWithUnderDeletionBlockGeneration );
816840 }
817841 }
818842}
0 commit comments