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 ;
5352
5453import java .io .IOException ;
5554import java .util .ArrayList ;
56- import java .util .Collection ;
5755import java .util .Collections ;
5856import java .util .EnumSet ;
5957import java .util .HashMap ;
@@ -997,12 +995,11 @@ private MetadataDiff(StreamInput in) throws IOException {
997995 multiProject = null ;
998996 } else {
999997 fromNodeBeforeMultiProjectsSupport = false ;
1000- // Repositories metadata is sent as Metadata#customs diff from old node. We need to
1001- // 1. Split it from the Metadata#customs diff
1002- // 2. Merge it into the default project's ProjectMetadataDiff
1003- final var bwcCustoms = maybeReadBwcCustoms (in );
1004- clusterCustoms = bwcCustoms .v1 ();
1005- final var defaultProjectCustoms = bwcCustoms .v2 ();
998+ clusterCustoms = DiffableUtils .readImmutableOpenMapDiff (
999+ in ,
1000+ DiffableUtils .getStringKeySerializer (),
1001+ CLUSTER_CUSTOM_VALUE_SERIALIZER
1002+ );
10061003
10071004 reservedStateMetadata = DiffableUtils .readImmutableOpenMapDiff (
10081005 in ,
@@ -1011,61 +1008,15 @@ private MetadataDiff(StreamInput in) throws IOException {
10111008 );
10121009
10131010 singleProject = null ;
1014- multiProject = readMultiProjectDiffs (in , defaultProjectCustoms );
1015- }
1016- }
1017-
1018- private static
1019- Tuple <
1020- MapDiff <String , ClusterCustom , ImmutableOpenMap <String , ClusterCustom >>,
1021- MapDiff <String , ProjectCustom , ImmutableOpenMap <String , ProjectCustom >>>
1022- maybeReadBwcCustoms (StreamInput in ) throws IOException {
1023- if (in .getTransportVersion ().before (TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM )) {
1024- return readBwcCustoms (in );
1025- } else {
1026- return new Tuple <>(
1027- DiffableUtils .readImmutableOpenMapDiff (in , DiffableUtils .getStringKeySerializer (), CLUSTER_CUSTOM_VALUE_SERIALIZER ),
1028- null
1011+ multiProject = DiffableUtils .readJdkMapDiff (
1012+ in ,
1013+ PROJECT_ID_SERIALIZER ,
1014+ ProjectMetadata ::readFrom ,
1015+ ProjectMetadata .ProjectMetadataDiff ::new
10291016 );
10301017 }
10311018 }
10321019
1033- @ SuppressWarnings ("unchecked" )
1034- private static MapDiff <ProjectId , ProjectMetadata , Map <ProjectId , ProjectMetadata >> readMultiProjectDiffs (
1035- StreamInput in ,
1036- MapDiff <String , ProjectCustom , ImmutableOpenMap <String , ProjectCustom >> defaultProjectCustoms
1037- ) throws IOException {
1038- final var multiProject = DiffableUtils .readJdkMapDiff (
1039- in ,
1040- PROJECT_ID_SERIALIZER ,
1041- ProjectMetadata ::readFrom ,
1042- ProjectMetadata .ProjectMetadataDiff ::new
1043- );
1044-
1045- // If the defaultProjectCustoms has content, the diff is read from an old node. We need to merge it into the
1046- // default project's ProjectMetadataDiff
1047- if (defaultProjectCustoms != null && defaultProjectCustoms .isEmpty () == false ) {
1048- return DiffableUtils .updateDiffsAndUpserts (multiProject , ProjectId .DEFAULT ::equals , (k , v ) -> {
1049- assert ProjectId .DEFAULT .equals (k ) : k ;
1050- assert v instanceof ProjectMetadata .ProjectMetadataDiff : v ;
1051- final var projectMetadataDiff = (ProjectMetadata .ProjectMetadataDiff ) v ;
1052- return projectMetadataDiff .withCustoms (
1053- DiffableUtils .merge (
1054- projectMetadataDiff .customs (),
1055- defaultProjectCustoms ,
1056- DiffableUtils .getStringKeySerializer (),
1057- BWC_CUSTOM_VALUE_SERIALIZER
1058- )
1059- );
1060- }, (k , v ) -> {
1061- assert ProjectId .DEFAULT .equals (k ) : k ;
1062- return ProjectMetadata .builder (v ).clearCustoms ().customs (defaultProjectCustoms .apply (v .customs ())).build ();
1063- });
1064- } else {
1065- return multiProject ;
1066- }
1067- }
1068-
10691020 @ SuppressWarnings ("unchecked" )
10701021 private static
10711022 Tuple <
@@ -1109,105 +1060,16 @@ public void writeTo(StreamOutput out) throws IOException {
11091060 buildUnifiedCustomDiff ().writeTo (out );
11101061 buildUnifiedReservedStateMetadataDiff ().writeTo (out );
11111062 } else {
1112- final var multiProjectToWrite = multiProject != null
1113- ? multiProject
1114- : DiffableUtils .singleEntryDiff (DEFAULT_PROJECT_ID , singleProject , PROJECT_ID_SERIALIZER );
1115-
1116- if (out .getTransportVersion ().before (TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM )) {
1117- writeDiffWithRepositoriesMetadataAsClusterCustom (out , clusterCustoms , multiProjectToWrite , reservedStateMetadata );
1063+ clusterCustoms .writeTo (out );
1064+ reservedStateMetadata .writeTo (out );
1065+ if (multiProject != null ) {
1066+ multiProject .writeTo (out );
11181067 } else {
1119- clusterCustoms .writeTo (out );
1120- reservedStateMetadata .writeTo (out );
1121- multiProjectToWrite .writeTo (out );
1068+ DiffableUtils .singleEntryDiff (DEFAULT_PROJECT_ID , singleProject , PROJECT_ID_SERIALIZER ).writeTo (out );
11221069 }
11231070 }
11241071 }
11251072
1126- @ SuppressWarnings ({ "rawtypes" , "unchecked" })
1127- private static void writeDiffWithRepositoriesMetadataAsClusterCustom (
1128- StreamOutput out ,
1129- MapDiff <String , ClusterCustom , ImmutableOpenMap <String , ClusterCustom >> clusterCustoms ,
1130- MapDiff <ProjectId , ProjectMetadata , Map <ProjectId , ProjectMetadata >> multiProject ,
1131- MapDiff <String , ReservedStateMetadata , ImmutableOpenMap <String , ReservedStateMetadata >> reservedStateMetadata
1132- ) throws IOException {
1133- assert out .getTransportVersion ().onOrAfter (TransportVersions .MULTI_PROJECT )
1134- && out .getTransportVersion ().before (TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM ) : out .getTransportVersion ();
1135-
1136- // For old nodes, RepositoriesMetadata needs to be sent as a cluster custom. This is possible when (a) the repositories
1137- // are defined only for the default project or (b) no repositories at all. What we need to do are:
1138- // 1. Iterate through the multi-project's MapDiff to extract the RepositoriesMetadata of the default project
1139- // 2. Throws if any repositories are found for non-default projects
1140- // 3. Merge default project's RepositoriesMetadata into Metadata#customs
1141- final var combineClustersCustoms = new SetOnce <MapDiff <String , MetadataCustom , Map <String , MetadataCustom >>>();
1142- final var updatedMultiProject = DiffableUtils .updateDiffsAndUpserts (multiProject , ignore -> true , (k , v ) -> {
1143- assert v instanceof ProjectMetadata .ProjectMetadataDiff : v ;
1144- final var projectMetadataDiff = (ProjectMetadata .ProjectMetadataDiff ) v ;
1145- final var bwcCustoms = DiffableUtils .split (
1146- projectMetadataDiff .customs (),
1147- RepositoriesMetadata .TYPE ::equals ,
1148- PROJECT_CUSTOM_VALUE_SERIALIZER ,
1149- type -> RepositoriesMetadata .TYPE .equals (type ) == false ,
1150- PROJECT_CUSTOM_VALUE_SERIALIZER
1151- );
1152- // Simply return if RepositoriesMetadata is not found
1153- if (bwcCustoms .v1 ().isEmpty ()) {
1154- return projectMetadataDiff ;
1155- }
1156- // RepositoriesMetadata can only be defined for the default project. Otherwise throw exception.
1157- if (ProjectId .DEFAULT .equals (k ) == false ) {
1158- throwForVersionBeforeRepositoriesMetadataMigration (out );
1159- }
1160- // RepositoriesMetadata is found for the default project as a diff, merge it into the Metadata#customs
1161- combineClustersCustoms .set (
1162- DiffableUtils .<String , MetadataCustom , ClusterCustom , ProjectCustom , Map <String , MetadataCustom >>merge (
1163- clusterCustoms ,
1164- bwcCustoms .v1 (),
1165- DiffableUtils .getStringKeySerializer ()
1166- )
1167- );
1168- return projectMetadataDiff .withCustoms (bwcCustoms .v2 ());
1169- }, (k , v ) -> {
1170- final ProjectCustom projectCustom = v .customs ().get (RepositoriesMetadata .TYPE );
1171- // Simply return if RepositoriesMetadata is not found
1172- if (projectCustom == null ) {
1173- return v ;
1174- }
1175- // RepositoriesMetadata can only be defined for the default project. Otherwise throw exception.
1176- if (ProjectId .DEFAULT .equals (k ) == false ) {
1177- throwForVersionBeforeRepositoriesMetadataMigration (out );
1178- }
1179- // RepositoriesMetadata found for the default project as an upsert, package it as MapDiff and merge into Metadata#customs
1180- combineClustersCustoms .set (
1181- DiffableUtils .<String , MetadataCustom , ClusterCustom , ProjectCustom , Map <String , MetadataCustom >>merge (
1182- clusterCustoms ,
1183- DiffableUtils .singleUpsertDiff (RepositoriesMetadata .TYPE , projectCustom , DiffableUtils .getStringKeySerializer ()),
1184- DiffableUtils .getStringKeySerializer ()
1185- )
1186- );
1187- return ProjectMetadata .builder (v ).removeCustom (RepositoriesMetadata .TYPE ).build ();
1188- });
1189-
1190- if (combineClustersCustoms .get () != null ) {
1191- combineClustersCustoms .get ().writeTo (out );
1192- } else {
1193- clusterCustoms .writeTo (out );
1194- }
1195-
1196- reservedStateMetadata .writeTo (out );
1197- updatedMultiProject .writeTo (out );
1198- }
1199-
1200- private static void throwForVersionBeforeRepositoriesMetadataMigration (StreamOutput out ) {
1201- assert out .getTransportVersion ().before (TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM ) : out .getTransportVersion ();
1202- throw new UnsupportedOperationException (
1203- "Serialize a diff with repositories defined for multiple projects requires version on or after ["
1204- + TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM
1205- + "], but got ["
1206- + out .getTransportVersion ()
1207- + "]"
1208- );
1209- }
1210-
12111073 @ SuppressWarnings ("unchecked" )
12121074 private Diff <ImmutableOpenMap <String , ?>> buildUnifiedCustomDiff () {
12131075 assert multiProject == null : "should only be used for single project metadata" ;
@@ -1361,34 +1223,19 @@ public static Metadata readFrom(StreamInput in) throws IOException {
13611223 builder .put (ReservedStateMetadata .readFrom (in ));
13621224 }
13631225 } else {
1364- List <ProjectCustom > defaultProjectCustoms = List .of ();
1365- if (in .getTransportVersion ().before (TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM )) {
1366- // Extract the default project's repositories metadata from the Metadata#customs from an old node
1367- defaultProjectCustoms = new ArrayList <>();
1368- readBwcCustoms (in , builder , defaultProjectCustoms ::add );
1369- assert defaultProjectCustoms .size () <= 1
1370- : "expect only a single default project custom for repository metadata, but got "
1371- + defaultProjectCustoms .stream ().map (ProjectCustom ::getWriteableName ).toList ();
1372- } else {
1373- readClusterCustoms (in , builder );
1374- }
1226+ readClusterCustoms (in , builder );
13751227
13761228 int reservedStateSize = in .readVInt ();
13771229 for (int i = 0 ; i < reservedStateSize ; i ++) {
13781230 builder .put (ReservedStateMetadata .readFrom (in ));
13791231 }
13801232
13811233 builder .projectMetadata (in .readMap (ProjectId ::readFrom , ProjectMetadata ::readFrom ));
1382- defaultProjectCustoms .forEach (c -> builder .getProject (ProjectId .DEFAULT ).putCustom (c .getWriteableName (), c ));
13831234 }
13841235 return builder .build ();
13851236 }
13861237
13871238 private static void readBwcCustoms (StreamInput in , Builder builder ) throws IOException {
1388- readBwcCustoms (in , builder , projectCustom -> builder .putProjectCustom (projectCustom .getWriteableName (), projectCustom ));
1389- }
1390-
1391- private static void readBwcCustoms (StreamInput in , Builder builder , Consumer <ProjectCustom > projectCustomConsumer ) throws IOException {
13921239 final Set <String > clusterScopedNames = in .namedWriteableRegistry ().getReaders (ClusterCustom .class ).keySet ();
13931240 final Set <String > projectScopedNames = in .namedWriteableRegistry ().getReaders (ProjectCustom .class ).keySet ();
13941241 final int count = in .readVInt ();
@@ -1404,9 +1251,9 @@ private static void readBwcCustoms(StreamInput in, Builder builder, Consumer<Pro
14041251 if (custom instanceof PersistentTasksCustomMetadata persistentTasksCustomMetadata ) {
14051252 final var tuple = persistentTasksCustomMetadata .split ();
14061253 builder .putCustom (tuple .v1 ().getWriteableName (), tuple .v1 ());
1407- projectCustomConsumer . accept ( tuple .v2 ());
1254+ builder . putProjectCustom ( tuple . v2 (). getWriteableName (), tuple .v2 ());
14081255 } else {
1409- projectCustomConsumer . accept ( custom );
1256+ builder . putProjectCustom ( custom . getWriteableName (), custom );
14101257 }
14111258 } else {
14121259 throw new IllegalArgumentException ("Unknown custom name [" + name + "]" );
@@ -1473,42 +1320,13 @@ public void writeTo(StreamOutput out) throws IOException {
14731320 combinedMetadata .addAll (singleProject .reservedStateMetadata ().values ());
14741321 out .writeCollection (combinedMetadata );
14751322 } else {
1476- if (out .getTransportVersion ().before (TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM )) {
1477- if (isSingleProject () || hasNoNonDefaultProjectRepositories (projects ().values ())) {
1478- // Repositories metadata must be sent as Metadata#customs for old nodes
1479- final List <VersionedNamedWriteable > combinedCustoms = new ArrayList <>(customs .size () + 1 );
1480- combinedCustoms .addAll (customs .values ());
1481- final ProjectCustom custom = getProject (ProjectId .DEFAULT ).custom (RepositoriesMetadata .TYPE );
1482- if (custom != null ) {
1483- combinedCustoms .add (custom );
1484- }
1485- VersionedNamedWriteable .writeVersionedWriteables (out , combinedCustoms );
1486- } else {
1487- throw new UnsupportedOperationException (
1488- "Serialize metadata with repositories defined for multiple projects requires version on or after ["
1489- + TransportVersions .REPOSITORIES_METADATA_AS_PROJECT_CUSTOM
1490- + "], but got ["
1491- + out .getTransportVersion ()
1492- + "]"
1493- );
1494- }
1495- } else {
1496- VersionedNamedWriteable .writeVersionedWriteables (out , customs .values ());
1497- }
1323+ VersionedNamedWriteable .writeVersionedWriteables (out , customs .values ());
14981324
14991325 out .writeCollection (reservedStateMetadata .values ());
15001326 out .writeMap (projectMetadata , StreamOutput ::writeWriteable , StreamOutput ::writeWriteable );
15011327 }
15021328 }
15031329
1504- /**
1505- * @return {@code true} iff no repositories are defined for non-default-projects.
1506- */
1507- private static boolean hasNoNonDefaultProjectRepositories (Collection <ProjectMetadata > projects ) {
1508- return projects .stream ()
1509- .allMatch (project -> ProjectId .DEFAULT .equals (project .id ()) || project .custom (RepositoriesMetadata .TYPE ) == null );
1510- }
1511-
15121330 public static Builder builder () {
15131331 return new Builder ();
15141332 }
0 commit comments