1111
1212import org .apache .logging .log4j .LogManager ;
1313import org .apache .logging .log4j .Logger ;
14- import org .apache .lucene .util .SetOnce ;
1514import org .elasticsearch .TransportVersions ;
1615import org .elasticsearch .cluster .ClusterState ;
1716import org .elasticsearch .cluster .Diff ;
5554
5655import java .io .IOException ;
5756import java .util .ArrayList ;
58- import java .util .Collection ;
5957import java .util .Collections ;
6058import java .util .EnumSet ;
6159import java .util .HashMap ;
@@ -999,12 +997,11 @@ private MetadataDiff(StreamInput in) throws IOException {
999997 multiProject = null ;
1000998 } else {
1001999 fromNodeBeforeMultiProjectsSupport = false ;
1002- // Repositories metadata is sent as Metadata#customs diff from old node. We need to
1003- // 1. Split it from the Metadata#customs diff
1004- // 2. Merge it into the default project's ProjectMetadataDiff
1005- final var bwcCustoms = maybeReadBwcCustoms (in );
1006- clusterCustoms = bwcCustoms .v1 ();
1007- final var defaultProjectCustoms = bwcCustoms .v2 ();
1000+ clusterCustoms = DiffableUtils .readImmutableOpenMapDiff (
1001+ in ,
1002+ DiffableUtils .getStringKeySerializer (),
1003+ CLUSTER_CUSTOM_VALUE_SERIALIZER
1004+ );
10081005
10091006 reservedStateMetadata = DiffableUtils .readImmutableOpenMapDiff (
10101007 in ,
@@ -1013,61 +1010,15 @@ private MetadataDiff(StreamInput in) throws IOException {
10131010 );
10141011
10151012 singleProject = null ;
1016- multiProject = readMultiProjectDiffs (in , defaultProjectCustoms );
1017- }
1018- }
1019-
1020- private static
1021- Tuple <
1022- MapDiff <String , ClusterCustom , ImmutableOpenMap <String , ClusterCustom >>,
1023- MapDiff <String , ProjectCustom , ImmutableOpenMap <String , ProjectCustom >>>
1024- maybeReadBwcCustoms (StreamInput in ) throws IOException {
1025- if (in .getTransportVersion ().before (TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM )) {
1026- return readBwcCustoms (in );
1027- } else {
1028- return new Tuple <>(
1029- DiffableUtils .readImmutableOpenMapDiff (in , DiffableUtils .getStringKeySerializer (), CLUSTER_CUSTOM_VALUE_SERIALIZER ),
1030- null
1013+ multiProject = DiffableUtils .readJdkMapDiff (
1014+ in ,
1015+ PROJECT_ID_SERIALIZER ,
1016+ ProjectMetadata ::readFrom ,
1017+ ProjectMetadata .ProjectMetadataDiff ::new
10311018 );
10321019 }
10331020 }
10341021
1035- @ SuppressWarnings ("unchecked" )
1036- private static MapDiff <ProjectId , ProjectMetadata , Map <ProjectId , ProjectMetadata >> readMultiProjectDiffs (
1037- StreamInput in ,
1038- MapDiff <String , ProjectCustom , ImmutableOpenMap <String , ProjectCustom >> defaultProjectCustoms
1039- ) throws IOException {
1040- final var multiProject = DiffableUtils .readJdkMapDiff (
1041- in ,
1042- PROJECT_ID_SERIALIZER ,
1043- ProjectMetadata ::readFrom ,
1044- ProjectMetadata .ProjectMetadataDiff ::new
1045- );
1046-
1047- // If the defaultProjectCustoms has content, the diff is read from an old node. We need to merge it into the
1048- // default project's ProjectMetadataDiff
1049- if (defaultProjectCustoms != null && defaultProjectCustoms .isEmpty () == false ) {
1050- return DiffableUtils .updateDiffsAndUpserts (multiProject , ProjectId .DEFAULT ::equals , (k , v ) -> {
1051- assert ProjectId .DEFAULT .equals (k ) : k ;
1052- assert v instanceof ProjectMetadata .ProjectMetadataDiff : v ;
1053- final var projectMetadataDiff = (ProjectMetadata .ProjectMetadataDiff ) v ;
1054- return projectMetadataDiff .withCustoms (
1055- DiffableUtils .merge (
1056- projectMetadataDiff .customs (),
1057- defaultProjectCustoms ,
1058- DiffableUtils .getStringKeySerializer (),
1059- BWC_CUSTOM_VALUE_SERIALIZER
1060- )
1061- );
1062- }, (k , v ) -> {
1063- assert ProjectId .DEFAULT .equals (k ) : k ;
1064- return ProjectMetadata .builder (v ).clearCustoms ().customs (defaultProjectCustoms .apply (v .customs ())).build ();
1065- });
1066- } else {
1067- return multiProject ;
1068- }
1069- }
1070-
10711022 @ SuppressWarnings ("unchecked" )
10721023 private static
10731024 Tuple <
@@ -1111,105 +1062,16 @@ public void writeTo(StreamOutput out) throws IOException {
11111062 buildUnifiedCustomDiff ().writeTo (out );
11121063 buildUnifiedReservedStateMetadataDiff ().writeTo (out );
11131064 } else {
1114- final var multiProjectToWrite = multiProject != null
1115- ? multiProject
1116- : DiffableUtils .singleEntryDiff (DEFAULT_PROJECT_ID , singleProject , PROJECT_ID_SERIALIZER );
1117-
1118- if (out .getTransportVersion ().before (TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM )) {
1119- writeDiffWithRepositoriesMetadataAsClusterCustom (out , clusterCustoms , multiProjectToWrite , reservedStateMetadata );
1065+ clusterCustoms .writeTo (out );
1066+ reservedStateMetadata .writeTo (out );
1067+ if (multiProject != null ) {
1068+ multiProject .writeTo (out );
11201069 } else {
1121- clusterCustoms .writeTo (out );
1122- reservedStateMetadata .writeTo (out );
1123- multiProjectToWrite .writeTo (out );
1070+ DiffableUtils .singleEntryDiff (DEFAULT_PROJECT_ID , singleProject , PROJECT_ID_SERIALIZER ).writeTo (out );
11241071 }
11251072 }
11261073 }
11271074
1128- @ SuppressWarnings ({ "rawtypes" , "unchecked" })
1129- private static void writeDiffWithRepositoriesMetadataAsClusterCustom (
1130- StreamOutput out ,
1131- MapDiff <String , ClusterCustom , ImmutableOpenMap <String , ClusterCustom >> clusterCustoms ,
1132- MapDiff <ProjectId , ProjectMetadata , Map <ProjectId , ProjectMetadata >> multiProject ,
1133- MapDiff <String , ReservedStateMetadata , ImmutableOpenMap <String , ReservedStateMetadata >> reservedStateMetadata
1134- ) throws IOException {
1135- assert out .getTransportVersion ().onOrAfter (TransportVersions .MULTI_PROJECT )
1136- && out .getTransportVersion ().before (TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM ) : out .getTransportVersion ();
1137-
1138- // For old nodes, RepositoriesMetadata needs to be sent as a cluster custom. This is possible when (a) the repositories
1139- // are defined only for the default project or (b) no repositories at all. What we need to do are:
1140- // 1. Iterate through the multi-project's MapDiff to extract the RepositoriesMetadata of the default project
1141- // 2. Throws if any repositories are found for non-default projects
1142- // 3. Merge default project's RepositoriesMetadata into Metadata#customs
1143- final var combineClustersCustoms = new SetOnce <MapDiff <String , MetadataCustom , Map <String , MetadataCustom >>>();
1144- final var updatedMultiProject = DiffableUtils .updateDiffsAndUpserts (multiProject , ignore -> true , (k , v ) -> {
1145- assert v instanceof ProjectMetadata .ProjectMetadataDiff : v ;
1146- final var projectMetadataDiff = (ProjectMetadata .ProjectMetadataDiff ) v ;
1147- final var bwcCustoms = DiffableUtils .split (
1148- projectMetadataDiff .customs (),
1149- RepositoriesMetadata .TYPE ::equals ,
1150- PROJECT_CUSTOM_VALUE_SERIALIZER ,
1151- type -> RepositoriesMetadata .TYPE .equals (type ) == false ,
1152- PROJECT_CUSTOM_VALUE_SERIALIZER
1153- );
1154- // Simply return if RepositoriesMetadata is not found
1155- if (bwcCustoms .v1 ().isEmpty ()) {
1156- return projectMetadataDiff ;
1157- }
1158- // RepositoriesMetadata can only be defined for the default project. Otherwise throw exception.
1159- if (ProjectId .DEFAULT .equals (k ) == false ) {
1160- throwForVersionBeforeRepositoriesMetadataMigration (out );
1161- }
1162- // RepositoriesMetadata is found for the default project as a diff, merge it into the Metadata#customs
1163- combineClustersCustoms .set (
1164- DiffableUtils .<String , MetadataCustom , ClusterCustom , ProjectCustom , Map <String , MetadataCustom >>merge (
1165- clusterCustoms ,
1166- bwcCustoms .v1 (),
1167- DiffableUtils .getStringKeySerializer ()
1168- )
1169- );
1170- return projectMetadataDiff .withCustoms (bwcCustoms .v2 ());
1171- }, (k , v ) -> {
1172- final ProjectCustom projectCustom = v .customs ().get (RepositoriesMetadata .TYPE );
1173- // Simply return if RepositoriesMetadata is not found
1174- if (projectCustom == null ) {
1175- return v ;
1176- }
1177- // RepositoriesMetadata can only be defined for the default project. Otherwise throw exception.
1178- if (ProjectId .DEFAULT .equals (k ) == false ) {
1179- throwForVersionBeforeRepositoriesMetadataMigration (out );
1180- }
1181- // RepositoriesMetadata found for the default project as an upsert, package it as MapDiff and merge into Metadata#customs
1182- combineClustersCustoms .set (
1183- DiffableUtils .<String , MetadataCustom , ClusterCustom , ProjectCustom , Map <String , MetadataCustom >>merge (
1184- clusterCustoms ,
1185- DiffableUtils .singleUpsertDiff (RepositoriesMetadata .TYPE , projectCustom , DiffableUtils .getStringKeySerializer ()),
1186- DiffableUtils .getStringKeySerializer ()
1187- )
1188- );
1189- return ProjectMetadata .builder (v ).removeCustom (RepositoriesMetadata .TYPE ).build ();
1190- });
1191-
1192- if (combineClustersCustoms .get () != null ) {
1193- combineClustersCustoms .get ().writeTo (out );
1194- } else {
1195- clusterCustoms .writeTo (out );
1196- }
1197-
1198- reservedStateMetadata .writeTo (out );
1199- updatedMultiProject .writeTo (out );
1200- }
1201-
1202- private static void throwForVersionBeforeRepositoriesMetadataMigration (StreamOutput out ) {
1203- assert out .getTransportVersion ().before (TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM ) : out .getTransportVersion ();
1204- throw new UnsupportedOperationException (
1205- "Serialize a diff with repositories defined for multiple projects requires version on or after ["
1206- + TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM
1207- + "], but got ["
1208- + out .getTransportVersion ()
1209- + "]"
1210- );
1211- }
1212-
12131075 @ SuppressWarnings ("unchecked" )
12141076 private Diff <ImmutableOpenMap <String , ?>> buildUnifiedCustomDiff () {
12151077 assert multiProject == null : "should only be used for single project metadata" ;
@@ -1363,34 +1225,19 @@ public static Metadata readFrom(StreamInput in) throws IOException {
13631225 builder .put (ReservedStateMetadata .readFrom (in ));
13641226 }
13651227 } else {
1366- List <ProjectCustom > defaultProjectCustoms = List .of ();
1367- if (in .getTransportVersion ().before (TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM )) {
1368- // Extract the default project's repositories metadata from the Metadata#customs from an old node
1369- defaultProjectCustoms = new ArrayList <>();
1370- readBwcCustoms (in , builder , defaultProjectCustoms ::add );
1371- assert defaultProjectCustoms .size () <= 1
1372- : "expect only a single default project custom for repository metadata, but got "
1373- + defaultProjectCustoms .stream ().map (ProjectCustom ::getWriteableName ).toList ();
1374- } else {
1375- readClusterCustoms (in , builder );
1376- }
1228+ readClusterCustoms (in , builder );
13771229
13781230 int reservedStateSize = in .readVInt ();
13791231 for (int i = 0 ; i < reservedStateSize ; i ++) {
13801232 builder .put (ReservedStateMetadata .readFrom (in ));
13811233 }
13821234
13831235 builder .projectMetadata (in .readMap (ProjectId ::readFrom , ProjectMetadata ::readFrom ));
1384- defaultProjectCustoms .forEach (c -> builder .getProject (ProjectId .DEFAULT ).putCustom (c .getWriteableName (), c ));
13851236 }
13861237 return builder .build ();
13871238 }
13881239
13891240 private static void readBwcCustoms (StreamInput in , Builder builder ) throws IOException {
1390- readBwcCustoms (in , builder , projectCustom -> builder .putProjectCustom (projectCustom .getWriteableName (), projectCustom ));
1391- }
1392-
1393- private static void readBwcCustoms (StreamInput in , Builder builder , Consumer <ProjectCustom > projectCustomConsumer ) throws IOException {
13941241 final Set <String > clusterScopedNames = in .namedWriteableRegistry ().getReaders (ClusterCustom .class ).keySet ();
13951242 final Set <String > projectScopedNames = in .namedWriteableRegistry ().getReaders (ProjectCustom .class ).keySet ();
13961243 final int count = in .readVInt ();
@@ -1406,9 +1253,9 @@ private static void readBwcCustoms(StreamInput in, Builder builder, Consumer<Pro
14061253 if (custom instanceof PersistentTasksCustomMetadata persistentTasksCustomMetadata ) {
14071254 final var tuple = persistentTasksCustomMetadata .split ();
14081255 builder .putCustom (tuple .v1 ().getWriteableName (), tuple .v1 ());
1409- projectCustomConsumer . accept ( tuple .v2 ());
1256+ builder . putProjectCustom ( tuple . v2 (). getWriteableName (), tuple .v2 ());
14101257 } else {
1411- projectCustomConsumer . accept ( custom );
1258+ builder . putProjectCustom ( custom . getWriteableName (), custom );
14121259 }
14131260 } else {
14141261 throw new IllegalArgumentException ("Unknown custom name [" + name + "]" );
@@ -1475,42 +1322,13 @@ public void writeTo(StreamOutput out) throws IOException {
14751322 combinedMetadata .addAll (singleProject .reservedStateMetadata ().values ());
14761323 out .writeCollection (combinedMetadata );
14771324 } else {
1478- if (out .getTransportVersion ().before (TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM )) {
1479- if (isSingleProject () || hasNoNonDefaultProjectRepositories (projects ().values ())) {
1480- // Repositories metadata must be sent as Metadata#customs for old nodes
1481- final List <VersionedNamedWriteable > combinedCustoms = new ArrayList <>(customs .size () + 1 );
1482- combinedCustoms .addAll (customs .values ());
1483- final ProjectCustom custom = getProject (ProjectId .DEFAULT ).custom (RepositoriesMetadata .TYPE );
1484- if (custom != null ) {
1485- combinedCustoms .add (custom );
1486- }
1487- VersionedNamedWriteable .writeVersionedWriteables (out , combinedCustoms );
1488- } else {
1489- throw new UnsupportedOperationException (
1490- "Serialize metadata with repositories defined for multiple projects requires version on or after ["
1491- + TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM
1492- + "], but got ["
1493- + out .getTransportVersion ()
1494- + "]"
1495- );
1496- }
1497- } else {
1498- VersionedNamedWriteable .writeVersionedWriteables (out , customs .values ());
1499- }
1325+ VersionedNamedWriteable .writeVersionedWriteables (out , customs .values ());
15001326
15011327 out .writeCollection (reservedStateMetadata .values ());
15021328 out .writeMap (projectMetadata , StreamOutput ::writeWriteable , StreamOutput ::writeWriteable );
15031329 }
15041330 }
15051331
1506- /**
1507- * @return {@code true} iff no repositories are defined for non-default-projects.
1508- */
1509- private static boolean hasNoNonDefaultProjectRepositories (Collection <ProjectMetadata > projects ) {
1510- return projects .stream ()
1511- .allMatch (project -> ProjectId .DEFAULT .equals (project .id ()) || project .custom (RepositoriesMetadata .TYPE ) == null );
1512- }
1513-
15141332 public static Builder builder () {
15151333 return new Builder ();
15161334 }
0 commit comments