This is an automated email from the ASF dual-hosted git repository.

amashenkov pushed a commit to branch ignite-25571
in repository https://gitbox.apache.org/repos/asf/ignite-3.git

commit 9fe314c833181113699f18b1326e0a6017ef5ac0
Author: amashenkov <[email protected]>
AuthorDate: Wed Jul 16 18:25:02 2025 +0300

    Support named lists
---
 .../ConfigurationCompatibilityTest.java            |   2 +-
 .../compatibility/framework/ConfigNode.java        |  20 +++++-
 .../framework/ConfigurationTreeComparator.java     |  38 +++++-----
 .../ConfigurationTreeComparatorSelfTest.java       |  77 +++++++++------------
 .../framework/ConfigurationTreeScanner.java        |   7 +-
 .../compatibility/configuration/snapshot.bin       | Bin 4020 -> 4039 bytes
 6 files changed, 78 insertions(+), 66 deletions(-)

diff --git 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/ConfigurationCompatibilityTest.java
 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/ConfigurationCompatibilityTest.java
index 73765825665..61c343a442a 100644
--- 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/ConfigurationCompatibilityTest.java
+++ 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/ConfigurationCompatibilityTest.java
@@ -114,7 +114,7 @@ public class ConfigurationCompatibilityTest extends 
IgniteAbstractTest {
         Set<ConfigurationModule> allModules = allModules();
         List<ConfigNode> snapshotMetadata = 
loadSnapshotFromResource(SNAPSHOTS_RESOURCE_LOCATION + fileName);
 
-        ComparisonContext ctx = new ComparisonContext(allModules);
+        ComparisonContext ctx = ComparisonContext.create(allModules);
 
         ConfigurationTreeComparator.ensureCompatible(snapshotMetadata, 
currentMetadata, ctx);
     }
diff --git 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigNode.java
 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigNode.java
index b964f9cedbd..0293a69fc81 100644
--- 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigNode.java
+++ 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigNode.java
@@ -200,6 +200,22 @@ public class ConfigNode {
         return flags.contains(Flags.IS_VALUE);
     }
 
+    /**
+     * Returns {@code true} if this node represents a named list node, {@code 
false} otherwise.
+     */
+    @JsonIgnore
+    public boolean isNamedNode() {
+        return flags.contains(Flags.IS_NAMED_NODE);
+    }
+
+    /**
+     * Returns {@code true} if this node represents an inner config node, 
{@code false} otherwise.
+     */
+    @JsonIgnore
+    public boolean isInnerNode() {
+        return flags.contains(Flags.IS_INNER_NODE);
+    }
+
     /**
      * Returns {@code true} if this node represents internal part of 
configuration, {@code false} otherwise.
      */
@@ -294,7 +310,9 @@ public class ConfigNode {
         IS_ROOT(1),
         IS_VALUE(1 << 1),
         IS_DEPRECATED(1 << 2),
-        IS_INTERNAL(1 << 3);
+        IS_INTERNAL(1 << 3),
+        IS_NAMED_NODE(1 << 4),
+        IS_INNER_NODE(1 << 5);
 
         private final int mask;
 
diff --git 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeComparator.java
 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeComparator.java
index 73d4b4b9b41..fd5d6a4d143 100644
--- 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeComparator.java
+++ 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeComparator.java
@@ -75,6 +75,8 @@ public class ConfigurationTreeComparator {
 
         @Override
         public void visit(ConfigNode node) {
+            assert node.isRoot() || node.isInnerNode() || node.isNamedNode() 
|| node.isValue();
+
             if (node.isValue() && !compContext.shouldIgnore(node.path())) {
                 validator.accept(node);
             }
@@ -147,8 +149,8 @@ public class ConfigurationTreeComparator {
      */
     private static boolean match(ConfigNode node, ConfigNode candidate) {
         return Objects.equals(candidate.kind(), node.kind())
-                && matchNames(candidate, node)
                 && validateFlags(candidate, node)
+                && matchNames(candidate, node)
                 && 
candidate.deletedPrefixes().containsAll(node.deletedPrefixes())
                 && (!node.isValue() || Objects.equals(candidate.type(), 
node.type())); // Value node types can be changed.
     }
@@ -177,7 +179,7 @@ public class ConfigurationTreeComparator {
 
     private static boolean matchNames(ConfigNode candidate, ConfigNode node) {
         return Objects.equals(candidate.name(), node.name())
-                || (node.isValue() && candidate.isValue() && 
compareUsingLegacyNames(candidate, node));
+                || compareUsingLegacyNames(candidate, node);
     }
 
     private static boolean compareUsingLegacyNames(ConfigNode candidate, 
ConfigNode node) {
@@ -187,6 +189,8 @@ public class ConfigurationTreeComparator {
     private static boolean validateFlags(ConfigNode candidate, ConfigNode 
node) {
         return node.isRoot() == candidate.isRoot()
                 && node.isValue() == candidate.isValue()
+                && node.isNamedNode() == candidate.isNamedNode()
+                && node.isInnerNode() == candidate.isInnerNode()
                 && (!candidate.isInternal() || node.isInternal()) // Public 
property\tree can't be hidden.
                 && (!node.isDeprecated() || candidate.isDeprecated()); // 
Deprecation shouldn't be removed.
     }
@@ -216,29 +220,27 @@ public class ConfigurationTreeComparator {
 
     /** Holder class for comparison context. */
     public static class ComparisonContext {
-        private final Set<ConfigurationModule> configurationModules;
-        private Collection<KeyIgnorer> deletedItems;
+        public static ComparisonContext create(Set<ConfigurationModule> 
configurationModules) {
+            Set<String> prefixes = configurationModules.stream()
+                    .map(ConfigurationModule::deletedPrefixes)
+                    .flatMap(Collection::stream)
+                    .collect(Collectors.toSet());
 
-        ComparisonContext() {
-            this.configurationModules = Set.of();
+            return create(prefixes);
         }
 
-        public ComparisonContext(Set<ConfigurationModule> 
configurationModules) {
-            this.configurationModules = configurationModules;
+        public static ComparisonContext create(Collection<String> prefixes) {
+            return new 
ComparisonContext(KeyIgnorer.fromDeletedPrefixes(prefixes));
         }
 
-        boolean shouldIgnore(String path) {
-            if (deletedItems == null) {
-                deletedItems = new ArrayList<>(configurationModules.size());
-
-                for (ConfigurationModule module : configurationModules) {
-                    KeyIgnorer keyIgnorer = 
KeyIgnorer.fromDeletedPrefixes(module.deletedPrefixes());
+        private final KeyIgnorer deletedItems;
 
-                    deletedItems.add(keyIgnorer);
-                }
-            }
+        ComparisonContext(KeyIgnorer deletedItems) {
+            this.deletedItems = deletedItems;
+        }
 
-            return deletedItems.stream().anyMatch(i -> i.shouldIgnore(path));
+        boolean shouldIgnore(String path) {
+            return deletedItems.shouldIgnore(path);
         }
     }
 }
diff --git 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeComparatorSelfTest.java
 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeComparatorSelfTest.java
index ab6e421e470..d4b1e28e449 100644
--- 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeComparatorSelfTest.java
+++ 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeComparatorSelfTest.java
@@ -94,7 +94,7 @@ public class ConfigurationTreeComparatorSelfTest {
         ));
 
         ConfigNode root2 = createRoot("root1");
-        ConfigNode child = new ConfigNode(root2, Map.of(Attributes.NAME, 
"child"), List.of(), EnumSet.noneOf(Flags.class));
+        ConfigNode child = new ConfigNode(root2, Map.of(Attributes.NAME, 
"child"), List.of(), EnumSet.of(Flags.IS_INNER_NODE));
         root2.addChildNodes(List.of(child));
         child.addChildNodes(
                 new ConfigNode(child, Map.of(Attributes.NAME, "child"), 
List.of(), EnumSet.of(Flags.IS_VALUE))
@@ -105,6 +105,26 @@ public class ConfigurationTreeComparatorSelfTest {
         assertIncompatible(root2, root1);
     }
 
+    @Test
+    void innerNodeTypeCantBeChanged() {
+        ConfigNode root1 = createRoot("root1");
+        ConfigNode root2 = createRoot("root1");
+
+        ConfigNode inner1 = new ConfigNode(root1, Map.of(Attributes.NAME, 
"inner"), List.of(), EnumSet.of(Flags.IS_NAMED_NODE));
+        ConfigNode inner2 = new ConfigNode(root2, Map.of(Attributes.NAME, 
"inner"), List.of(), EnumSet.of(Flags.IS_INNER_NODE));
+
+        ConfigNode leafNode1 = new ConfigNode(inner1, Map.of(Attributes.NAME, 
"child"), List.of(), EnumSet.of(Flags.IS_VALUE));
+        ConfigNode leafNode2 = new ConfigNode(inner2, Map.of(Attributes.NAME, 
"child"), List.of(), EnumSet.of(Flags.IS_VALUE));
+
+        root1.addChildNodes(inner1);
+        root2.addChildNodes(inner2);
+        inner1.addChildNodes(leafNode1);
+        inner2.addChildNodes(leafNode2);
+
+        assertIncompatible(root1, root2);
+        assertIncompatible(root2, root1);
+    }
+
     @Test
     void propertyCantBeRemoved() {
         ConfigNode root1 = createRoot("root1");
@@ -218,7 +238,7 @@ public class ConfigurationTreeComparatorSelfTest {
 
         Set<ConfigurationModule> allModules = Set.of(configModule);
 
-        assertCompatible(snapshotMetadata, currentMetadata, new 
ComparisonContext(allModules));
+        assertCompatible(snapshotMetadata, currentMetadata, 
ComparisonContext.create(allModules));
 
         // missed deleted properties
         configModule = new ConfigurationModule() {
@@ -235,7 +255,7 @@ public class ConfigurationTreeComparatorSelfTest {
 
         allModules = Set.of(configModule);
 
-        assertIncompatible(snapshotMetadata, currentMetadata, new 
ComparisonContext(allModules));
+        assertIncompatible(snapshotMetadata, currentMetadata, 
ComparisonContext.create(allModules));
     }
 
     /**
@@ -248,7 +268,7 @@ public class ConfigurationTreeComparatorSelfTest {
                 EnumSet.of(Flags.IS_ROOT));
 
         ConfigNode compoundProp = new ConfigNode(root, Map.of(Attributes.NAME, 
"list"), List.of(),
-                EnumSet.of(Flags.IS_INTERNAL));
+                EnumSet.of(Flags.IS_INNER_NODE));
 
         ConfigNode firstMemberOfCompoundProp = new ConfigNode(compoundProp, 
Map.of(Attributes.NAME, "firstProperty"), List.of(),
                 EnumSet.of(Flags.IS_VALUE));
@@ -266,44 +286,15 @@ public class ConfigurationTreeComparatorSelfTest {
                 EnumSet.of(Flags.IS_ROOT));
 
         compoundProp = new ConfigNode(root, Map.of(Attributes.NAME, "list"), 
List.of(),
-                EnumSet.of(Flags.IS_INTERNAL));
+                EnumSet.of(Flags.IS_INNER_NODE));
 
         root.addChildNodes(List.of(compoundProp));
 
         List<ConfigNode> currentMetadata = List.of(root);
 
-        ConfigurationModule configModule = new ConfigurationModule() {
-            @Override
-            public ConfigurationType type() {
-                return ConfigurationType.LOCAL;
-            }
-
-            @Override
-            public Collection<String> deletedPrefixes() {
-                return List.of("root.list.*");
-            }
-        };
-
-        Set<ConfigurationModule> allModules = Set.of(configModule);
-
-        assertCompatible(snapshotMetadata, currentMetadata, new 
ComparisonContext(allModules));
-
+        assertCompatible(snapshotMetadata, currentMetadata, 
ComparisonContext.create(List.of("root.list.*")));
         // missed deleted properties
-        configModule = new ConfigurationModule() {
-            @Override
-            public ConfigurationType type() {
-                return ConfigurationType.LOCAL;
-            }
-
-            @Override
-            public Collection<String> deletedPrefixes() {
-                return List.of("root.list_notExist.*");
-            }
-        };
-
-        allModules = Set.of(configModule);
-
-        assertIncompatible(snapshotMetadata, currentMetadata, new 
ComparisonContext(allModules));
+        assertIncompatible(snapshotMetadata, currentMetadata, 
ComparisonContext.create(List.of("root.list_notExist.*")));
     }
 
     @Test
@@ -406,10 +397,8 @@ public class ConfigurationTreeComparatorSelfTest {
     }
 
     /**
-     * Test scenario. <br>
-     * config ver1 has property : prop1 <br>
-     * config ver2 has renamed property : prop1 -> prop2 <br>
-     * config ver3 has deleted property : prop1, prop2 <br>
+     * Test scenario. <br> config ver1 has property : prop1 <br> config ver2 
has renamed property : prop1 -> prop2 <br> config ver3 has
+     * deleted property : prop1, prop2 <br>
      * <br>
      * Check config transitions are possible: ver1 -> ver2, ver1 -> ver3, ver2 
-> ver3
      */
@@ -461,8 +450,8 @@ public class ConfigurationTreeComparatorSelfTest {
         Set<ConfigurationModule> allModules = Set.of(configModule);
 
         assertCompatible(metadataVer1, metadataVer2);
-        assertCompatible(metadataVer1, metadataVer3, new 
ComparisonContext(allModules));
-        assertCompatible(metadataVer2, metadataVer3, new 
ComparisonContext(allModules));
+        assertCompatible(metadataVer1, metadataVer3, 
ComparisonContext.create(allModules));
+        assertCompatible(metadataVer2, metadataVer3, 
ComparisonContext.create(allModules));
     }
 
     private static ConfigNode createRoot(String name) {
@@ -483,7 +472,7 @@ public class ConfigurationTreeComparatorSelfTest {
     }
 
     private static void assertCompatible(List<ConfigNode> oldConfig, 
List<ConfigNode> newConfig) {
-        assertCompatible(oldConfig, newConfig, new ComparisonContext());
+        assertCompatible(oldConfig, newConfig, 
ComparisonContext.create(List.of()));
     }
 
     private static void assertCompatible(List<ConfigNode> oldConfig, 
List<ConfigNode> newConfig, ComparisonContext compContext) {
@@ -495,7 +484,7 @@ public class ConfigurationTreeComparatorSelfTest {
     }
 
     private static void assertIncompatible(List<ConfigNode> oldConfig, 
List<ConfigNode> newConfig) {
-        assertIncompatible(oldConfig, newConfig, new ComparisonContext());
+        assertIncompatible(oldConfig, newConfig, 
ComparisonContext.create(List.of()));
     }
 
     private static void assertIncompatible(List<ConfigNode> oldConfig, 
List<ConfigNode> newConfig, ComparisonContext compContext) {
diff --git 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeScanner.java
 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeScanner.java
index b5795826ffe..57994671dd3 100644
--- 
a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeScanner.java
+++ 
b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/compatibility/framework/ConfigurationTreeScanner.java
@@ -191,8 +191,11 @@ public class ConfigurationTreeScanner {
     private static EnumSet<ConfigNode.Flags> extractFlags(Field field) {
         EnumSet<ConfigNode.Flags> flags = 
EnumSet.noneOf(ConfigNode.Flags.class);
 
-        if (!field.isAnnotationPresent(NamedConfigValue.class)
-                && !field.isAnnotationPresent(ConfigValue.class)) {
+        if (field.isAnnotationPresent(NamedConfigValue.class)) {
+            flags.add(Flags.IS_NAMED_NODE);
+        } else if (field.isAnnotationPresent(ConfigValue.class)) {
+            flags.add(Flags.IS_INNER_NODE);
+        } else {
             flags.add(Flags.IS_VALUE);
         }
 
diff --git 
a/modules/runner/src/test/resources/compatibility/configuration/snapshot.bin 
b/modules/runner/src/test/resources/compatibility/configuration/snapshot.bin
index a0ed7892a13..6e100c42880 100644
Binary files 
a/modules/runner/src/test/resources/compatibility/configuration/snapshot.bin 
and 
b/modules/runner/src/test/resources/compatibility/configuration/snapshot.bin 
differ

Reply via email to