4747import org .elasticsearch .common .io .stream .StreamOutput ;
4848import org .elasticsearch .common .io .stream .VersionedNamedWriteable ;
4949import org .elasticsearch .common .io .stream .Writeable ;
50+ import org .elasticsearch .common .settings .Settings ;
5051import org .elasticsearch .common .util .Maps ;
5152import org .elasticsearch .common .xcontent .ChunkedToXContent ;
5253import org .elasticsearch .common .xcontent .ChunkedToXContentHelper ;
@@ -192,6 +193,8 @@ public CompatibilityVersions read(StreamInput in, String key) throws IOException
192193
193194 private final boolean wasReadFromDiff ;
194195
196+ private final Map <ProjectId , Settings > projectsSettings ;
197+
195198 // built on demand
196199 private volatile RoutingNodes routingNodes ;
197200
@@ -208,6 +211,7 @@ public ClusterState(long version, String stateUUID, ClusterState state) {
208211 state .blocks (),
209212 state .customs (),
210213 false ,
214+ state .projectsSettings ,
211215 state .routingNodes
212216 );
213217 }
@@ -224,6 +228,7 @@ public ClusterState(
224228 ClusterBlocks blocks ,
225229 Map <String , Custom > customs ,
226230 boolean wasReadFromDiff ,
231+ Map <ProjectId , Settings > projectsSettings ,
227232 @ Nullable RoutingNodes routingNodes
228233 ) {
229234 this .version = version ;
@@ -237,6 +242,7 @@ public ClusterState(
237242 this .blocks = blocks ;
238243 this .customs = customs ;
239244 this .wasReadFromDiff = wasReadFromDiff ;
245+ this .projectsSettings = projectsSettings ;
240246 this .routingNodes = routingNodes ;
241247 assert assertConsistentRoutingNodes (routingTable , nodes , routingNodes );
242248 assert assertConsistentProjectState (routingTable , metadata );
@@ -404,6 +410,14 @@ public RoutingTable routingTable(ProjectId projectId) {
404410 return routingTable .routingTable (projectId );
405411 }
406412
413+ public Settings projectSettings (ProjectId projectId ) {
414+ return projectsSettings .getOrDefault (projectId , Settings .EMPTY );
415+ }
416+
417+ public Map <ProjectId , Settings > projectsSettings () {
418+ return projectsSettings ;
419+ }
420+
407421 @ Deprecated (forRemoval = true )
408422 public RoutingTable routingTable () {
409423 return routingTable .getRoutingTable ();
@@ -672,7 +686,8 @@ public enum Metric {
672686 METADATA ("metadata" ),
673687 ROUTING_TABLE ("routing_table" ),
674688 ROUTING_NODES ("routing_nodes" ),
675- CUSTOMS ("customs" );
689+ CUSTOMS ("customs" ),
690+ PROJECTS_SETTINGS ("projects_settings" );
676691
677692 private static final Map <String , Metric > valueToEnum ;
678693
@@ -849,7 +864,22 @@ public Iterator<? extends ToXContent> toXContentChunked(ToXContent.Params outerP
849864 customs .entrySet ().iterator (),
850865 e -> ChunkedToXContentHelper .object (e .getKey (), e .getValue ().toXContentChunked (outerParams ))
851866 )
852- : Collections .emptyIterator ()
867+ : Collections .emptyIterator (),
868+
869+ chunkedSection (
870+ multiProject && metrics .contains (Metric .PROJECTS_SETTINGS ),
871+ (builder , params ) -> builder .startArray ("projects_settings" ),
872+ projectsSettings .entrySet ().iterator (),
873+
874+ entry -> Iterators .single ((builder , params ) -> {
875+ builder .startObject ();
876+ builder .field ("id" , entry .getKey ());
877+ builder .startObject ("settings" );
878+ entry .getValue ().toXContent (builder , new ToXContent .MapParams (Collections .singletonMap ("flat_settings" , "true" )));
879+ return builder .endObject ().endObject ();
880+ }),
881+ (builder , params ) -> builder .endArray ()
882+ )
853883 );
854884 }
855885
@@ -1006,6 +1036,7 @@ public static class Builder {
10061036 private final Map <String , Set <String >> nodeFeatures ;
10071037 private ClusterBlocks blocks = ClusterBlocks .EMPTY_CLUSTER_BLOCK ;
10081038 private final ImmutableOpenMap .Builder <String , Custom > customs ;
1039+ private final ImmutableOpenMap .Builder <ProjectId , Settings > projectsSettings ;
10091040 private boolean fromDiff ;
10101041
10111042 public Builder (ClusterState state ) {
@@ -1021,11 +1052,13 @@ public Builder(ClusterState state) {
10211052 this .blocks = state .blocks ();
10221053 this .customs = ImmutableOpenMap .builder (state .customs ());
10231054 this .fromDiff = false ;
1055+ this .projectsSettings = ImmutableOpenMap .builder (state .projectsSettings );
10241056 }
10251057
10261058 public Builder (ClusterName clusterName ) {
10271059 this .compatibilityVersions = new HashMap <>();
10281060 this .nodeFeatures = new HashMap <>();
1061+ this .projectsSettings = ImmutableOpenMap .builder ();
10291062 customs = ImmutableOpenMap .builder ();
10301063 this .clusterName = clusterName ;
10311064 }
@@ -1130,6 +1163,16 @@ public Builder putRoutingTable(ProjectId projectId, RoutingTable routingTable) {
11301163 return routingTable (globalRoutingTableBuilder .put (projectId , routingTable ).build ());
11311164 }
11321165
1166+ public Builder putProjectSettings (ProjectId projectId , Settings settings ) {
1167+ projectsSettings .put (projectId , settings );
1168+ return this ;
1169+ }
1170+
1171+ public Builder projectsSettings (Map <ProjectId , Settings > projectsSettings ) {
1172+ this .projectsSettings .putAllFromMap (projectsSettings );
1173+ return this ;
1174+ }
1175+
11331176 public Builder metadata (Metadata .Builder metadataBuilder ) {
11341177 return metadata (metadataBuilder .build ());
11351178 }
@@ -1234,6 +1277,7 @@ public ClusterState build() {
12341277 metadata != null ? blocks .initializeProjects (metadata .projects ().keySet ()) : blocks ,
12351278 customs .build (),
12361279 fromDiff ,
1280+ projectsSettings .build (),
12371281 routingNodes
12381282 );
12391283 }
@@ -1285,6 +1329,9 @@ public static ClusterState readFrom(StreamInput in, DiscoveryNode localNode) thr
12851329 Custom customIndexMetadata = in .readNamedWriteable (Custom .class );
12861330 builder .putCustom (customIndexMetadata .getWriteableName (), customIndexMetadata );
12871331 }
1332+ if (in .getTransportVersion ().onOrAfter (TransportVersions .CLUSTER_STATE_PROJECTS_SETTINGS )) {
1333+ builder .projectsSettings (in .readMap (ProjectId ::readFrom , Settings ::readSettingsFromStream ));
1334+ }
12881335 return builder .build ();
12891336 }
12901337
@@ -1306,9 +1353,23 @@ public void writeTo(StreamOutput out) throws IOException {
13061353 clusterFeatures .writeTo (out );
13071354 blocks .writeTo (out );
13081355 VersionedNamedWriteable .writeVersionedWritables (out , customs );
1356+ if (out .getTransportVersion ().onOrAfter (TransportVersions .CLUSTER_STATE_PROJECTS_SETTINGS )) {
1357+ out .writeMap (projectsSettings );
1358+ }
13091359 }
13101360
13111361 private static class ClusterStateDiff implements Diff <ClusterState > {
1362+ private static final DiffableUtils .ValueSerializer <ProjectId , Settings > SETTINGS_SERIALIZER = new DiffableUtils .DiffableValueSerializer <>() {
1363+ @ Override
1364+ public Settings read (StreamInput in , ProjectId key ) throws IOException {
1365+ return Settings .readSettingsFromStream (in );
1366+ }
1367+
1368+ @ Override
1369+ public Diff <Settings > readDiff (StreamInput in , ProjectId key ) throws IOException {
1370+ return Settings .readSettingsDiffFromStream (in );
1371+ }
1372+ };
13121373
13131374 private final long toVersion ;
13141375
@@ -1331,6 +1392,8 @@ private static class ClusterStateDiff implements Diff<ClusterState> {
13311392
13321393 private final Diff <Map <String , Custom >> customs ;
13331394
1395+ private final DiffableUtils .MapDiff <ProjectId , Settings , Map <ProjectId , Settings >> projectsSettings ;
1396+
13341397 ClusterStateDiff (ClusterState before , ClusterState after ) {
13351398 fromUuid = before .stateUUID ;
13361399 toUuid = after .stateUUID ;
@@ -1348,6 +1411,7 @@ private static class ClusterStateDiff implements Diff<ClusterState> {
13481411 metadata = after .metadata .diff (before .metadata );
13491412 blocks = after .blocks .diff (before .blocks );
13501413 customs = DiffableUtils .diff (before .customs , after .customs , DiffableUtils .getStringKeySerializer (), CUSTOM_VALUE_SERIALIZER );
1414+ projectsSettings = DiffableUtils .diff (before .projectsSettings , after .projectsSettings , ProjectId .PROJECT_ID_SERIALIZER , SETTINGS_SERIALIZER );
13511415 }
13521416
13531417 ClusterStateDiff (StreamInput in , DiscoveryNode localNode ) throws IOException {
@@ -1364,6 +1428,11 @@ private static class ClusterStateDiff implements Diff<ClusterState> {
13641428 metadata = Metadata .readDiffFrom (in );
13651429 blocks = ClusterBlocks .readDiffFrom (in );
13661430 customs = DiffableUtils .readJdkMapDiff (in , DiffableUtils .getStringKeySerializer (), CUSTOM_VALUE_SERIALIZER );
1431+ if (in .getTransportVersion ().onOrAfter (TransportVersions .CLUSTER_STATE_PROJECTS_SETTINGS )) {
1432+ projectsSettings = DiffableUtils .readJdkMapDiff (in , ProjectId .PROJECT_ID_SERIALIZER , SETTINGS_SERIALIZER );
1433+ } else {
1434+ projectsSettings = DiffableUtils .emptyDiff ();
1435+ }
13671436 }
13681437
13691438 @ Override
@@ -1380,6 +1449,9 @@ public void writeTo(StreamOutput out) throws IOException {
13801449 metadata .writeTo (out );
13811450 blocks .writeTo (out );
13821451 customs .writeTo (out );
1452+ if (out .getTransportVersion ().onOrAfter (TransportVersions .CLUSTER_STATE_PROJECTS_SETTINGS )) {
1453+ projectsSettings .writeTo (out );
1454+ }
13831455 }
13841456
13851457 @ Override
@@ -1401,6 +1473,7 @@ public ClusterState apply(ClusterState state) {
14011473 builder .metadata (metadata .apply (state .metadata ));
14021474 builder .blocks (blocks .apply (state .blocks ));
14031475 builder .customs (customs .apply (state .customs ));
1476+ builder .projectsSettings (this .projectsSettings .apply (state .projectsSettings ));
14041477 builder .fromDiff (state );
14051478 return builder .build ();
14061479 }
0 commit comments