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

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


The following commit(s) were added to refs/heads/main by this push:
     new a29a3e3fee2 IGNITE-25458 Fix deletion of renamed configuration from 
the storage (#6028)
a29a3e3fee2 is described below

commit a29a3e3fee2176b9e41ee6a2defaf45ddcf5ae60
Author: Ivan Bessonov <[email protected]>
AuthorDate: Mon Jun 16 10:29:43 2025 +0300

    IGNITE-25458 Fix deletion of renamed configuration from the storage (#6028)
---
 .../configuration/ConfigurationChanger.java        |  69 ++++++------
 .../configuration/util/ConfigurationFlattener.java | 122 +++++++++++++-------
 .../configuration/util/ConfigurationUtil.java      |  77 +++++++++++++
 .../util/KeysTrackingConfigurationVisitor.java     | 125 ++++++++++-----------
 .../configuration/RenamedConfigurationTest.java    | 106 +++++++++++++++--
 .../configuration/util/ConfigurationUtilTest.java  |  33 ++++--
 .../storage/LocalFileConfigurationStorage.java     |   3 +-
 7 files changed, 380 insertions(+), 155 deletions(-)

diff --git 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationChanger.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationChanger.java
index e4c40dbd1f9..8e51df632e0 100644
--- 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationChanger.java
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationChanger.java
@@ -34,6 +34,7 @@ import static 
org.apache.ignite.internal.configuration.util.ConfigurationUtil.dr
 import static 
org.apache.ignite.internal.configuration.util.ConfigurationUtil.escape;
 import static 
org.apache.ignite.internal.configuration.util.ConfigurationUtil.fillFromPrefixMap;
 import static 
org.apache.ignite.internal.configuration.util.ConfigurationUtil.findEx;
+import static 
org.apache.ignite.internal.configuration.util.ConfigurationUtil.ignoreLegacyKeys;
 import static 
org.apache.ignite.internal.configuration.util.ConfigurationUtil.toPrefixMap;
 import static 
org.apache.ignite.internal.util.CompletableFutures.nullCompletedFuture;
 
@@ -44,9 +45,11 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.NavigableMap;
 import java.util.NoSuchElementException;
 import java.util.RandomAccess;
 import java.util.StringJoiner;
+import java.util.TreeMap;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -71,7 +74,6 @@ import 
org.apache.ignite.internal.configuration.tree.ConstructableTreeNode;
 import org.apache.ignite.internal.configuration.tree.InnerNode;
 import org.apache.ignite.internal.configuration.tree.NamedListNode;
 import org.apache.ignite.internal.configuration.util.ConfigurationUtil;
-import 
org.apache.ignite.internal.configuration.util.KeysTrackingConfigurationVisitor;
 import 
org.apache.ignite.internal.configuration.validation.ConfigurationValidator;
 import org.apache.ignite.internal.lang.IgniteInternalException;
 import org.apache.ignite.internal.lang.NodeStoppingException;
@@ -156,8 +158,11 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
         /** Immutable forest, so to say. */
         private final SuperRoot roots;
 
+        /** Change ID that corresponds to this state. */
+        private final long changeId;
+
         /** Full storage data. */
-        private final Data data;
+        private final NavigableMap<String, ? extends Serializable> storageData;
 
         /** Future that signifies update of current configuration. */
         private final CompletableFuture<Void> changeFuture = new 
CompletableFuture<>();
@@ -167,12 +172,19 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
          *
          * @param rootsWithoutDefaults Forest without the defaults
          * @param roots Forest with the defaults filled in
-         * @param data Configuration storage state.
+         * @param changeId Change ID that corresponds to this state.
+         * @param storageData Full storage data.
          */
-        private StorageRoots(SuperRoot rootsWithoutDefaults, SuperRoot roots, 
Data data) {
+        private StorageRoots(
+                SuperRoot rootsWithoutDefaults,
+                SuperRoot roots,
+                long changeId,
+                NavigableMap<String, ? extends Serializable> storageData
+        ) {
             this.rootsWithoutDefaults = rootsWithoutDefaults;
             this.roots = roots;
-            this.data = data;
+            this.changeId = changeId;
+            this.storageData = storageData;
 
             makeImmutable(roots);
             makeImmutable(rootsWithoutDefaults);
@@ -315,7 +327,7 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
         // The root WITHOUT the defaults is used to calculate which properties 
to write to the underlying storage,
         // in other words it allows us to persist the defaults from the code.
         // After the storage listener fires for the first time both roots are 
supposed to become equal.
-        storageRoots = new StorageRoots(superRootNoDefaults, superRoot, data);
+        storageRoots = new StorageRoots(superRootNoDefaults, superRoot, 
data.changeId(), new TreeMap<>(data.values()));
 
         storage.registerConfigurationListener(configurationStorageListener());
 
@@ -333,7 +345,7 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
     private void persistModifiedConfiguration() {
         // If the storage version is 0, it indicates that the storage is empty.
         // In this case, write the defaults along with the initial 
configuration.
-        ConfigurationSource cfgSrc = storageRoots.data.changeId() == 0 ? 
initialConfiguration : ConfigurationUtil.EMPTY_CFG_SRC;
+        ConfigurationSource cfgSrc = storageRoots.changeId == 0 ? 
initialConfiguration : ConfigurationUtil.EMPTY_CFG_SRC;
 
         changeInternally(cfgSrc, true)
                 .whenComplete((v, e) -> {
@@ -619,7 +631,7 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
             // This read and the following comparison MUST be performed while 
holding read lock.
             StorageRoots localRoots = storageRoots;
 
-            if (localRoots.data.changeId() < storageRevision) {
+            if (localRoots.changeId < storageRevision) {
                 // Need to wait for the configuration updates from the 
storage, then try to update again (loop).
                 return localRoots.changeFuture.thenCompose(v -> 
changeInternally(src, onStartup));
             }
@@ -639,7 +651,7 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
             Map<String, Serializable> allChanges = createFlattenedUpdatesMap(
                     localRoots.rootsWithoutDefaults,
                     changes,
-                    localRoots.data.values()
+                    localRoots.storageData
             );
 
             if (onStartup) {
@@ -663,7 +675,7 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
             // still try to write the empty update, because local 
configuration can be obsolete. If this is the case, then the CAS will
             // fail and the update will be recalculated and there is a chance 
that the new local configuration will produce a non-empty
             // update.
-            return storage.write(allChanges, localRoots.data.changeId())
+            return storage.write(allChanges, localRoots.changeId)
                     .thenCompose(casWroteSuccessfully -> {
                         if (casWroteSuccessfully) {
                             return localRoots.changeFuture;
@@ -709,10 +721,9 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
 
                 // We need to ignore deletion of deprecated values.
                 ignoreDeleted(changedValues, keyIgnorer);
-                // We need to ignore deletion of legacy values.
-                ignoreLegacyKeys(oldStorageRoots, changedValues);
 
                 Map<String, ?> dataValuesPrefixMap = 
toPrefixMap(changedValues);
+                ignoreLegacyKeys(oldStorageRoots.roots, dataValuesPrefixMap);
 
                 compressDeletedEntries(dataValuesPrefixMap);
 
@@ -721,7 +732,8 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
 
                 long newChangeId = changedEntries.changeId();
 
-                var newStorageRoots = new StorageRoots(newSuperNoDefaults, 
newSuperRoot, mergeData(oldStorageRoots.data, changedEntries));
+                NavigableMap<String, ? extends Serializable> newData = 
mergeData(oldStorageRoots.storageData, changedEntries.values());
+                var newStorageRoots = new StorageRoots(newSuperNoDefaults, 
newSuperRoot, newChangeId, newData);
 
                 rwLock.writeLock().lock();
 
@@ -751,12 +763,13 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
         };
     }
 
-    private static Data mergeData(Data currentData, Data delta) {
-        assert delta.changeId() > currentData.changeId() : 
currentData.changeId() + " " + delta.changeId();
-
-        Map<String, Serializable> newState = new 
HashMap<>(currentData.values());
+    private static NavigableMap<String, ? extends Serializable> mergeData(
+            NavigableMap<String, ? extends Serializable> currentData,
+            Map<String, ? extends Serializable> delta
+    ) {
+        NavigableMap<String, Serializable> newState = new 
TreeMap<>(currentData);
 
-        for (Entry<String, ? extends Serializable> entry : 
delta.values().entrySet()) {
+        for (Entry<String, ? extends Serializable> entry : delta.entrySet()) {
             if (entry.getValue() == null) {
                 newState.remove(entry.getKey());
             } else {
@@ -764,25 +777,15 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
             }
         }
 
-        return new Data(newState, delta.changeId());
-    }
-
-    private static void ignoreLegacyKeys(StorageRoots oldStorageRoots, 
Map<String, ? extends Serializable> changedValues) {
-        oldStorageRoots.roots.traverseChildren(new 
KeysTrackingConfigurationVisitor<>() {
-            @Override
-            protected Object doVisitLeafNode(Field field, String key, 
Serializable val) {
-                processLegacyPaths(changedValues::remove);
-
-                return null;
-            }
-        }, true);
+        return newState;
     }
 
     /**
-     * Remove keys from {@code allChanges}, that are associated with nulls in 
this map, and already absent in {@link StorageRoots#data}.
+     * Remove keys from {@code allChanges}, that are associated with nulls in 
this map, and already absent in
+     * {@link StorageRoots#storageData}.
      */
     private static void dropUnnecessarilyDeletedKeys(Map<String, Serializable> 
allChanges, StorageRoots localRoots) {
-        allChanges.entrySet().removeIf(entry -> entry.getValue() == null && 
!localRoots.data.values().containsKey(entry.getKey()));
+        allChanges.entrySet().removeIf(entry -> entry.getValue() == null && 
!localRoots.storageData.containsKey(entry.getKey()));
     }
 
     /**
@@ -798,7 +801,7 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
         return configurationUpdateListener.onConfigurationUpdated(
                 null,
                 storageRoots.roots,
-                storageRoots.data.changeId(),
+                storageRoots.changeId,
                 notificationCount
         );
     }
diff --git 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/ConfigurationFlattener.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/ConfigurationFlattener.java
index 72e26208e9b..ff92a8a6d18 100644
--- 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/ConfigurationFlattener.java
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/ConfigurationFlattener.java
@@ -26,11 +26,15 @@ import java.util.ArrayDeque;
 import java.util.Deque;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.NavigableMap;
 import java.util.Objects;
+import java.util.SortedMap;
 import java.util.UUID;
+import java.util.function.Supplier;
 import org.apache.ignite.internal.configuration.SuperRoot;
 import org.apache.ignite.internal.configuration.tree.InnerNode;
 import org.apache.ignite.internal.configuration.tree.NamedListNode;
+import org.jetbrains.annotations.Nullable;
 
 /** Utility class that has {@link 
ConfigurationFlattener#createFlattenedUpdatesMap} method. */
 public class ConfigurationFlattener {
@@ -44,7 +48,7 @@ public class ConfigurationFlattener {
     public static Map<String, Serializable> createFlattenedUpdatesMap(
             SuperRoot curRoot,
             SuperRoot updates,
-            Map<String, ? extends Serializable> storageData
+            NavigableMap<String, ? extends Serializable> storageData
     ) {
         // Resulting map.
         Map<String, Serializable> resMap = new HashMap<>();
@@ -96,7 +100,7 @@ public class ConfigurationFlattener {
         private final Map<String, Serializable> resMap;
 
         /** Map with values in the configuration storage. */
-        private final Map<String, ? extends Serializable> storageData;
+        private final NavigableMap<String, ? extends Serializable> storageData;
 
         /** Flag indicates that "old" and "new" trees are literally the same 
at the moment. */
         private boolean singleTreeTraversal;
@@ -116,33 +120,48 @@ public class ConfigurationFlattener {
         FlattenerVisitor(
                 Deque<InnerNode> oldInnerNodesStack,
                 Map<String, Serializable> resMap,
-                Map<String, ? extends Serializable> storageData
+                NavigableMap<String, ? extends Serializable> storageData
         ) {
             this.oldInnerNodesStack = oldInnerNodesStack;
             this.resMap = resMap;
             this.storageData = storageData;
         }
 
+        private void putToMap(boolean mustOverride, boolean delete, 
Supplier<String> key, @Nullable Serializable newVal) {
+            if (mustOverride) {
+                // This branch does the unconditional update, because it is 
known that the value must be updated.
+                resMap.put(key.get(), delete ? null : newVal);
+            } else {
+                String currentKey = key.get();
+
+                // Here the value must not be updated, but it could be 
updated. This code corresponds to a scenario where node restarts on
+                // a new version of Ignite and the name of the configuration 
key is changed to a new one. There's a separate piece of code
+                // that deletes all usages of old name. This particular code 
makes sure that we re-write each value with their new keys.
+                if (!storageData.containsKey(currentKey)) {
+                    resMap.put(currentKey, newVal);
+                }
+            }
+        }
+
         /** {@inheritDoc} */
         @Override
         public Void doVisitLeafNode(Field field, String key, Serializable 
newVal) {
-            boolean isDeprecated = field.isAnnotationPresent(Deprecated.class);
-
             // Read same value from old tree.
             Serializable oldVal = 
oldInnerNodesStack.element().traverseChild(key, 
ConfigurationUtil.leafNodeVisitor(), true);
 
             // Do not put duplicates into the resulting map.
-            if (isDeprecated || singleTreeTraversal || 
!Objects.deepEquals(oldVal, newVal)) {
-                boolean deletion = this.deletion || isDeprecated;
+            putToMap(singleTreeTraversal || !Objects.deepEquals(oldVal, 
newVal), deletion, this::currentKey, newVal);
 
-                resMap.put(currentKey(), deletion ? null : newVal);
-            }
+            return null;
+        }
 
-            processLegacyPaths(legacyKey -> {
-                if (storageData.containsKey(legacyKey)) {
-                    resMap.put(legacyKey, null);
-                }
-            });
+        @Override
+        protected Object doVisitLegacyLeafNode(Field field, String key, 
Serializable val, boolean isDeprecated) {
+            String currentKey = currentKey();
+
+            if (storageData.containsKey(currentKey)) {
+                resMap.put(currentKey, null);
+            }
 
             return null;
         }
@@ -150,8 +169,6 @@ public class ConfigurationFlattener {
         /** {@inheritDoc} */
         @Override
         public Void doVisitInnerNode(Field field, String key, InnerNode 
newNode) {
-            boolean isDeprecated = field != null && 
field.isAnnotationPresent(Deprecated.class);
-
             // Read same node from old tree.
             InnerNode oldNode = 
oldInnerNodesStack.element().traverseChild(key, 
ConfigurationUtil.innerNodeVisitor(), true);
 
@@ -162,16 +179,14 @@ public class ConfigurationFlattener {
             }
 
             if (oldNode == null) {
-                visitAsymmetricInnerNode(newNode, isDeprecated);
+                visitAsymmetricInnerNode(newNode, false);
             } else if (oldNode.schemaType() != newNode.schemaType()) {
                 // At the moment, we do not separate the general fields from 
the fields of
                 // specific instances of the polymorphic configuration, so we 
will assume
                 // that all the fields have changed, perhaps we will fix this 
later.
                 visitAsymmetricInnerNode(oldNode, true);
 
-                visitAsymmetricInnerNode(newNode, isDeprecated);
-            } else if (isDeprecated) {
-                visitAsymmetricInnerNode(newNode, true);
+                visitAsymmetricInnerNode(newNode, false);
             } else {
                 oldInnerNodesStack.push(oldNode);
 
@@ -183,11 +198,16 @@ public class ConfigurationFlattener {
             return null;
         }
 
+        @Override
+        protected Object doVisitLegacyInnerNode(Field field, String key, 
InnerNode node, boolean isDeprecated) {
+            dropOutdatedData();
+
+            return null;
+        }
+
         /** {@inheritDoc} */
         @Override
         public Void doVisitNamedListNode(Field field, String key, 
NamedListNode<?> newNode) {
-            boolean isDeprecated = field.isAnnotationPresent(Deprecated.class);
-
             // Read same named list node from old tree.
             NamedListNode<?> oldNode =
                     oldInnerNodesStack.element().traverseChild(key, 
ConfigurationUtil.namedListNodeVisitor(), true);
@@ -204,7 +224,7 @@ public class ConfigurationFlattener {
                 String namedListFullKey = currentKey();
 
                 withTracking(field, newNodeInternalId.toString(), false, 
false, () -> {
-                    InnerNode newNamedElement = isDeprecated ? null : 
newNode.getInnerNode(newNodeKey);
+                    InnerNode newNamedElement = 
newNode.getInnerNode(newNodeKey);
 
                     String oldNodeKey = 
oldNode.keyByInternalId(newNodeInternalId);
                     InnerNode oldNamedElement = 
oldNode.getInnerNode(oldNodeKey);
@@ -217,14 +237,14 @@ public class ConfigurationFlattener {
                     if (newNamedElement == null) {
                         visitAsymmetricInnerNode(oldNamedElement, true);
                     } else if (oldNamedElement == null) {
-                        visitAsymmetricInnerNode(newNamedElement, 
isDeprecated);
+                        visitAsymmetricInnerNode(newNamedElement, false);
                     } else if (newNamedElement.schemaType() != 
oldNamedElement.schemaType()) {
                         // At the moment, we do not separate the general 
fields from the fields of
                         // specific instances of the polymorphic 
configuration, so we will assume
                         // that all the fields have changed, perhaps we will 
fix this later.
                         visitAsymmetricInnerNode(oldNamedElement, true);
 
-                        visitAsymmetricInnerNode(newNamedElement, 
isDeprecated);
+                        visitAsymmetricInnerNode(newNamedElement, false);
                     } else {
                         oldInnerNodesStack.push(oldNamedElement);
 
@@ -237,20 +257,20 @@ public class ConfigurationFlattener {
                     Integer oldIdx = oldKeysToOrderIdxMap == null ? null : 
oldKeysToOrderIdxMap.get(newNodeKey);
 
                     // We should "persist" changed indexes only.
-                    if (!Objects.equals(newIdx, oldIdx) || singleTreeTraversal 
|| newNamedElement == null) {
-                        String orderKey = currentKey() + 
NamedListNode.ORDER_IDX;
-
-                        resMap.put(orderKey, deletion || newNamedElement == 
null ? null : newIdx);
-                    }
+                    putToMap(
+                            !Objects.equals(newIdx, oldIdx) || 
singleTreeTraversal || newNamedElement == null,
+                            deletion || newNamedElement == null,
+                            () -> currentKey() + NamedListNode.ORDER_IDX,
+                            newIdx
+                    );
 
                     // If it's creation / deletion / rename.
-                    if (singleTreeTraversal || oldNamedElement == null || 
newNamedElement == null
-                            || !oldNodeKey.equals(newNodeKey)
-                    ) {
-                        String nameKey = currentKey() + NamedListNode.NAME;
-
-                        resMap.put(nameKey, deletion || newNamedElement == 
null ? null : newNodeKey);
-                    }
+                    putToMap(
+                            singleTreeTraversal || oldNamedElement == null || 
newNamedElement == null || !oldNodeKey.equals(newNodeKey),
+                            deletion || newNamedElement == null,
+                            () -> currentKey() + NamedListNode.NAME,
+                            newNodeKey
+                    );
 
                     if (singleTreeTraversal) {
                         if (deletion) {
@@ -276,6 +296,12 @@ public class ConfigurationFlattener {
                         }
                     }
 
+                    // Don't use "putToMap" method here because it would be 
too complicated due to all the conditions above.
+                    String idKey = idKey(namedListFullKey, newNodeKey);
+                    if (!storageData.containsKey(idKey)) {
+                        resMap.put(idKey, newNodeInternalId);
+                    }
+
                     return null;
                 });
             }
@@ -283,10 +309,30 @@ public class ConfigurationFlattener {
             return null;
         }
 
+        @Override
+        protected Object doVisitLegacyNamedListNode(Field field, String key, 
NamedListNode<?> node, boolean isDeprecated) {
+            dropOutdatedData();
+
+            return null;
+        }
+
+        private void dropOutdatedData() {
+            String currentKey = currentKey();
+            SortedMap<String, ? extends Serializable> tailMap = 
storageData.tailMap(currentKey);
+
+            for (String storageKey : tailMap.keySet()) {
+                if (!storageKey.startsWith(currentKey)) {
+                    break;
+                }
+
+                resMap.put(storageKey, null);
+            }
+        }
+
         /**
          * Creates key {@code prefix.<ids>.nodeKey}, escaping {@code nodeKey} 
before appending it.
          */
-        private String idKey(String prefix, String nodeKey) {
+        private static String idKey(String prefix, String nodeKey) {
             return prefix + NamedListNode.IDS + KEY_SEPARATOR + 
escape(nodeKey);
         }
 
diff --git 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/ConfigurationUtil.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/ConfigurationUtil.java
index f2890cc5734..54fad1800de 100644
--- 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/ConfigurationUtil.java
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/ConfigurationUtil.java
@@ -64,8 +64,10 @@ import 
org.apache.ignite.configuration.annotation.NamedConfigValue;
 import org.apache.ignite.configuration.annotation.PolymorphicConfig;
 import org.apache.ignite.configuration.annotation.PolymorphicConfigInstance;
 import org.apache.ignite.configuration.annotation.PolymorphicId;
+import org.apache.ignite.configuration.annotation.PublicName;
 import org.apache.ignite.configuration.annotation.Value;
 import org.apache.ignite.internal.configuration.DynamicConfiguration;
+import org.apache.ignite.internal.configuration.SuperRoot;
 import org.apache.ignite.internal.configuration.direct.KeyPathNode;
 import org.apache.ignite.internal.configuration.storage.ConfigurationStorage;
 import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
@@ -940,6 +942,81 @@ public class ConfigurationUtil {
         };
     }
 
+    /**
+     * Removes {@code null} values that correspond to non-deprecated legacy 
keys from the configuration tree.
+     *
+     * @param roots Super root.
+     * @param prefixMap Mutable prefix map with updates received from the 
storage.
+     * @see PublicName#legacyNames()
+     */
+    public static void ignoreLegacyKeys(SuperRoot roots, Map<String, ?> 
prefixMap) {
+        roots.traverseChildren(new KeysTrackingConfigurationVisitor<>() {
+            /** Map that correspond to current recursive call. */
+            private Map<String, ?> currentMap = prefixMap;
+
+            @Override
+            protected Object doVisitLegacyLeafNode(Field field, String key, 
Serializable val, boolean isDeprecated) {
+                if (!isDeprecated) {
+                    currentMap.remove(key);
+                }
+
+                return null;
+            }
+
+            @Override
+            protected Object doVisitInnerNode(Field field, String key, 
InnerNode node) {
+                if (!currentMap.containsKey(key)) {
+                    return null;
+                }
+
+                Map<String, ?> prev = currentMap;
+                currentMap = (Map<String, ?>) currentMap.get(key);
+
+                node.traverseChildren(this, true);
+
+                currentMap = prev;
+
+                return null;
+            }
+
+            @Override
+            protected Object doVisitLegacyInnerNode(Field field, String key, 
InnerNode node, boolean isDeprecated) {
+                currentMap.remove(key);
+
+                return null;
+            }
+
+            @Override
+            protected Object doVisitNamedListNode(Field field, String key, 
NamedListNode<?> node) {
+                if (!currentMap.containsKey(key)) {
+                    return null;
+                }
+
+                Map<String, ?> prev = currentMap;
+                currentMap = (Map<String, ? extends Serializable>) 
currentMap.get(key);
+
+                for (String namedListKey : node.namedListKeys()) {
+                    withTracking(field, 
node.internalId(namedListKey).toString(), false, false, () -> {
+                        doVisitInnerNode(field, namedListKey, 
node.getInnerNode(namedListKey));
+
+                        return null;
+                    });
+                }
+
+                currentMap = prev;
+
+                return null;
+            }
+
+            @Override
+            protected Object doVisitLegacyNamedListNode(Field field, String 
key, NamedListNode<?> node, boolean isDeprecated) {
+                currentMap.remove(key);
+
+                return null;
+            }
+        }, true);
+    }
+
     /**
      * Leaf configuration source.
      */
diff --git 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/KeysTrackingConfigurationVisitor.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/KeysTrackingConfigurationVisitor.java
index 0a5405f3f35..cd36d4bf635 100644
--- 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/KeysTrackingConfigurationVisitor.java
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/KeysTrackingConfigurationVisitor.java
@@ -18,8 +18,6 @@
 package org.apache.ignite.internal.configuration.util;
 
 import static 
org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.legacyNames;
-import static 
org.apache.ignite.internal.configuration.util.ConfigurationUtil.appendKey;
-import static 
org.apache.ignite.internal.configuration.util.ConfigurationUtil.join;
 import static org.apache.ignite.internal.util.ArrayUtils.STRING_EMPTY_ARRAY;
 
 import java.io.Serializable;
@@ -27,7 +25,6 @@ import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.function.Consumer;
 import java.util.function.Supplier;
 import org.apache.ignite.internal.configuration.tree.ConfigurationVisitor;
 import org.apache.ignite.internal.configuration.tree.InnerNode;
@@ -41,19 +38,31 @@ public abstract class KeysTrackingConfigurationVisitor<T> 
implements Configurati
     /** Current keys list, almost the same as {@link #currentKey}. */
     private final List<String> currentPath = new ArrayList<>();
 
-    /** For every part of the current path stores corresponding legacy names. 
*/
-    private final List<String[]> currentLegacyNames = new ArrayList<>();
+    private static boolean isDeprecated(Field field) {
+        return field != null && field.getAnnotation(Deprecated.class) != null;
+    }
 
-    /** Total amount of legacy names, corresponding to the current path. */
-    private int currentLegacyNamesCount = 0;
+    private static String[] getLegacyNames(Field field) {
+        return field == null ? STRING_EMPTY_ARRAY : legacyNames(field);
+    }
 
     /** {@inheritDoc} */
     @Override
     public final T visitLeafNode(Field field, String key, Serializable val) {
+        for (String legacyKey : getLegacyNames(field)) {
+            int prevPos = startVisit(field, legacyKey, false, true);
+
+            try {
+                doVisitLegacyLeafNode(field, legacyKey, val, false);
+            } finally {
+                endVisit(prevPos);
+            }
+        }
+
         int prevPos = startVisit(field, key, false, true);
 
         try {
-            return doVisitLeafNode(field, key, val);
+            return isDeprecated(field) ? doVisitLegacyLeafNode(field, key, 
val, true) : doVisitLeafNode(field, key, val);
         } finally {
             endVisit(prevPos);
         }
@@ -62,10 +71,20 @@ public abstract class KeysTrackingConfigurationVisitor<T> 
implements Configurati
     /** {@inheritDoc} */
     @Override
     public final T visitInnerNode(Field field, String key, InnerNode node) {
+        for (String legacyKey : getLegacyNames(field)) {
+            int prevPos = startVisit(field, legacyKey, false, false);
+
+            try {
+                doVisitLegacyInnerNode(field, legacyKey, node, false);
+            } finally {
+                endVisit(prevPos);
+            }
+        }
+
         int prevPos = startVisit(field, key, false, false);
 
         try {
-            return doVisitInnerNode(field, key, node);
+            return isDeprecated(field) ? doVisitLegacyInnerNode(field, key, 
node, true) : doVisitInnerNode(field, key, node);
         } finally {
             endVisit(prevPos);
         }
@@ -74,10 +93,20 @@ public abstract class KeysTrackingConfigurationVisitor<T> 
implements Configurati
     /** {@inheritDoc} */
     @Override
     public final T visitNamedListNode(Field field, String key, 
NamedListNode<?> node) {
+        for (String legacyKey : getLegacyNames(field)) {
+            int prevPos = startVisit(field, legacyKey, false, false);
+
+            try {
+                doVisitLegacyNamedListNode(field, legacyKey, node, false);
+            } finally {
+                endVisit(prevPos);
+            }
+        }
+
         int prevPos = startVisit(field, key, false, false);
 
         try {
-            return doVisitNamedListNode(field, key, node);
+            return isDeprecated(field) ? doVisitLegacyNamedListNode(field, 
key, node, true) : doVisitNamedListNode(field, key, node);
         } finally {
             endVisit(prevPos);
         }
@@ -94,6 +123,13 @@ public abstract class KeysTrackingConfigurationVisitor<T> 
implements Configurati
         return null;
     }
 
+    /**
+     * Almost the same as {@link #doVisitLeafNode(Field, String, 
Serializable)}, but used for legacy fields.
+     */
+    protected T doVisitLegacyLeafNode(Field field, String key, Serializable 
val, boolean isDeprecated) {
+        return null;
+    }
+
     /**
      * To be used instead of {@link ConfigurationVisitor#visitInnerNode(Field, 
String, InnerNode)}.
      *
@@ -107,6 +143,13 @@ public abstract class KeysTrackingConfigurationVisitor<T> 
implements Configurati
         return null;
     }
 
+    /**
+     * Almost the same as {@link #doVisitInnerNode(Field, String, InnerNode)}, 
but used for legacy fields.
+     */
+    protected T doVisitLegacyInnerNode(Field field, String key, InnerNode 
node, boolean isDeprecated) {
+        return null;
+    }
+
     /**
      * To be used instead of {@link ConfigurationVisitor#visitNamedListNode}}.
      *
@@ -128,6 +171,13 @@ public abstract class KeysTrackingConfigurationVisitor<T> 
implements Configurati
         return null;
     }
 
+    /**
+     * Almost the same as {@link #doVisitNamedListNode(Field, String, 
NamedListNode)}, but used for legacy fields.
+     */
+    protected T doVisitLegacyNamedListNode(Field field, String key, 
NamedListNode<?> node, boolean isDeprecated) {
+        return null;
+    }
+
     /**
      * Tracks passed key to reflect it in {@link #currentKey()} and {@link 
#currentPath()}.
      *
@@ -185,11 +235,6 @@ public abstract class KeysTrackingConfigurationVisitor<T> 
implements Configurati
 
         currentPath.add(key);
 
-        String[] legacyNames = field == null ? STRING_EMPTY_ARRAY : 
legacyNames(field);
-
-        currentLegacyNames.add(legacyNames);
-        currentLegacyNamesCount += legacyNames.length;
-
         return previousKeyLength;
     }
 
@@ -202,55 +247,5 @@ public abstract class KeysTrackingConfigurationVisitor<T> 
implements Configurati
         currentKey.setLength(previousKeyLength);
 
         currentPath.remove(currentPath.size() - 1);
-
-        String[] legacyNames = 
currentLegacyNames.remove(currentLegacyNames.size() - 1);
-        currentLegacyNamesCount -= legacyNames.length;
-    }
-
-    /** Calls consumer for all variations of legacy paths, i.e. to remove them 
from the storage. */
-    protected void processLegacyPaths(Consumer<String> legacyKeyConsumer) {
-        // Current path doesn't contain any legacy names.
-        if (currentLegacyNamesCount == 0) {
-            return;
-        }
-
-        processLegacyPaths(new ArrayList<>(), legacyKeyConsumer);
-    }
-
-    private void processLegacyPaths(List<String> path, Consumer<String> 
legacyKeyConsumer) {
-        // We reached the leaf. If path joined with leaf name != current key, 
it is legacy and should be processed.
-        if (path.size() == currentPath().size() - 1) {
-            for (String leafName : currentLegacyNames.get(currentPath().size() 
- 1)) {
-                processLeaf(path, legacyKeyConsumer, leafName);
-            }
-
-            // Process current name for cases when legacy name was in the 
middle of the path.
-            processLeaf(path, legacyKeyConsumer, 
currentPath().get(currentPath().size() - 1));
-
-            return;
-        }
-
-        // For inner nodes we should all legacy names and current name.
-        for (String innerNodeName : currentLegacyNames.get(path.size())) {
-            path.add(innerNodeName);
-
-            processLegacyPaths(path, legacyKeyConsumer);
-
-            path.remove(path.size() - 1);
-        }
-
-        path.add(currentPath.get(path.size()));
-
-        processLegacyPaths(path, legacyKeyConsumer);
-
-        path.remove(path.size() - 1);
-    }
-
-    private void processLeaf(List<String> path, Consumer<String> 
legacyKeyConsumer, String leafName) {
-        String key = join(appendKey(path, leafName));
-
-        if (!key.equals(currentKey())) {
-            legacyKeyConsumer.accept(key);
-        }
     }
 }
diff --git 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/RenamedConfigurationTest.java
 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/RenamedConfigurationTest.java
index f19758b62b2..7a8542f4d1f 100644
--- 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/RenamedConfigurationTest.java
+++ 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/RenamedConfigurationTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.configuration;
 
+import static java.util.Map.entry;
 import static 
org.apache.ignite.configuration.annotation.ConfigurationType.LOCAL;
 import static 
org.apache.ignite.internal.configuration.hocon.HoconConverter.hoconSource;
 import static 
org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willBe;
@@ -24,10 +25,18 @@ import static 
org.apache.ignite.internal.testframework.matchers.CompletableFutur
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.nullValue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import com.typesafe.config.ConfigFactory;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
+import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import org.apache.ignite.configuration.RootKey;
 import org.apache.ignite.configuration.annotation.Config;
 import org.apache.ignite.configuration.annotation.ConfigValue;
@@ -41,13 +50,13 @@ import 
org.apache.ignite.configuration.annotation.PublicName;
 import org.apache.ignite.configuration.annotation.Value;
 import org.apache.ignite.internal.configuration.storage.Data;
 import 
org.apache.ignite.internal.configuration.storage.TestConfigurationStorage;
+import org.apache.ignite.internal.configuration.util.ConfigurationUtil;
 import 
org.apache.ignite.internal.configuration.validation.TestConfigurationValidator;
 import org.apache.ignite.internal.manager.ComponentContext;
 import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
 class RenamedConfigurationTest extends BaseIgniteAbstractTest {
@@ -156,14 +165,26 @@ class RenamedConfigurationTest extends 
BaseIgniteAbstractTest {
     }
 
     @Test
-    @Disabled("IGNITE-25458")
     public void testNamedListLegacyNameIsRecognisedOnStartup() {
         assertThat(
                 
registry.getConfiguration(RenamedTestNewConfiguration.KEY).newListName().get("listInstance").newName().value(),
                 equalTo("oldValue")
         );
 
-        // TODO IGNITE-25458 Add check that old value is deleted
+        validateStorageContent(
+                entry("key.newInnerName.name", "oldDefault"),
+                entry("key.newInnerName.newName", "oldDefault"),
+                entry("key.newListName.$listId.<name>", "listInstance"),
+                entry("key.newListName.$listId.<order>", 0),
+                entry("key.newListName.$listId.name", "oldDefault"),
+                entry("key.newListName.$listId.newName", "oldValue"),
+                entry("key.newListName.<ids>.listInstance", "$listId"),
+                entry("key.newPolymorphicName.<ids>.polymorphicType", 
"$polymorphicId"),
+                entry("key.newPolymorphicName.$polymorphicId.<name>", 
"polymorphicType"),
+                entry("key.newPolymorphicName.$polymorphicId.<order>", 0),
+                entry("key.newPolymorphicName.$polymorphicId.newName", 
"oldValue"),
+                entry("key.newPolymorphicName.$polymorphicId.type", 
"polymorphicType")
+        );
     }
 
     @Test
@@ -178,18 +199,43 @@ class RenamedConfigurationTest extends 
BaseIgniteAbstractTest {
                 equalTo(newValue)
         );
 
-        // TODO IGNITE-25458 Add check that old value is deleted
+        validateStorageContent(
+                entry("key.newInnerName.name", "oldDefault"),
+                entry("key.newInnerName.newName", "oldDefault"),
+                entry("key.newListName.$listId.<name>", "listInstance"),
+                entry("key.newListName.$listId.<order>", 0),
+                entry("key.newListName.$listId.name", "oldDefault"),
+                entry("key.newListName.$listId.newName", newValue),
+                entry("key.newListName.<ids>.listInstance", "$listId"),
+                entry("key.newPolymorphicName.<ids>.polymorphicType", 
"$polymorphicId"),
+                entry("key.newPolymorphicName.$polymorphicId.<name>", 
"polymorphicType"),
+                entry("key.newPolymorphicName.$polymorphicId.<order>", 0),
+                entry("key.newPolymorphicName.$polymorphicId.newName", 
"oldValue"),
+                entry("key.newPolymorphicName.$polymorphicId.type", 
"polymorphicType")
+        );
     }
 
     @Test
-    @Disabled("IGNITE-25458")
     public void testPolymorphicLegacyNameIsRecognisedOnStartup() {
         assertThat(
                 
registry.getConfiguration(RenamedTestNewConfiguration.KEY).newPolymorphicName().get("polymorphicType").newName().value(),
                 equalTo("oldValue")
         );
 
-        // TODO IGNITE-25458 Add check that old value is deleted
+        validateStorageContent(
+                entry("key.newInnerName.name", "oldDefault"),
+                entry("key.newInnerName.newName", "oldDefault"),
+                entry("key.newListName.$listId.<name>", "listInstance"),
+                entry("key.newListName.$listId.<order>", 0),
+                entry("key.newListName.$listId.name", "oldDefault"),
+                entry("key.newListName.$listId.newName", "oldValue"),
+                entry("key.newListName.<ids>.listInstance", "$listId"),
+                entry("key.newPolymorphicName.<ids>.polymorphicType", 
"$polymorphicId"),
+                entry("key.newPolymorphicName.$polymorphicId.<name>", 
"polymorphicType"),
+                entry("key.newPolymorphicName.$polymorphicId.<order>", 0),
+                entry("key.newPolymorphicName.$polymorphicId.newName", 
"oldValue"),
+                entry("key.newPolymorphicName.$polymorphicId.type", 
"polymorphicType")
+        );
     }
 
     @Test
@@ -203,7 +249,53 @@ class RenamedConfigurationTest extends 
BaseIgniteAbstractTest {
                 equalTo(newValue)
         );
 
-        // TODO IGNITE-25458 Add check that old value is deleted
+        validateStorageContent(
+                entry("key.newInnerName.name", "oldDefault"),
+                entry("key.newInnerName.newName", "oldDefault"),
+                entry("key.newListName.$listId.<name>", "listInstance"),
+                entry("key.newListName.$listId.<order>", 0),
+                entry("key.newListName.$listId.name", "oldDefault"),
+                entry("key.newListName.$listId.newName", "oldValue"),
+                entry("key.newListName.<ids>.listInstance", "$listId"),
+                entry("key.newPolymorphicName.<ids>.polymorphicType", 
"$polymorphicId"),
+                entry("key.newPolymorphicName.$polymorphicId.<name>", 
"polymorphicType"),
+                entry("key.newPolymorphicName.$polymorphicId.<order>", 0),
+                entry("key.newPolymorphicName.$polymorphicId.newName", 
newValue),
+                entry("key.newPolymorphicName.$polymorphicId.type", 
"polymorphicType")
+        );
+    }
+
+    /**
+     * Validates that the storage content matches the expected values. Because 
storage contains several "dynamic" values, whose IDs are not
+     * constants, we denote them as strings {@code "$listId"} and {@code 
"$polymorphicId"}.All occasions of these strings will be replaced
+     * with real values of these identifiers.
+     */
+    @SafeVarargs
+    private void validateStorageContent(Map.Entry<String, Serializable> 
...values) {
+        CompletableFuture<Data> dataFuture = storage.readDataOnRecovery();
+        assertThat(dataFuture, willCompleteSuccessfully());
+
+        RenamedTestNewView node = 
registry.getConfiguration(RenamedTestNewConfiguration.KEY).value();
+
+        UUID listId = ConfigurationUtil.internalId(node.newListName(), 
"listInstance");
+        UUID polymorphicId = 
ConfigurationUtil.internalId(node.newPolymorphicName(), "polymorphicType");
+
+        Function<Entry<String, ? extends Serializable>, String> keyMapper = e 
->
+                e.getKey().replace("$listId", 
listId.toString()).replace("$polymorphicId", polymorphicId.toString());
+
+        Function<Entry<String, ? extends Serializable>, Serializable> 
valueMapper = e -> {
+            if ("$listId".equals(e.getValue())) {
+                return listId;
+            } else if ("$polymorphicId".equals(e.getValue())) {
+                return polymorphicId;
+            } else {
+                return e.getValue();
+            }
+        };
+
+        Map<String, ? extends Serializable> expectedMap = 
Stream.of(values).collect(Collectors.toMap(keyMapper, valueMapper));
+
+        assertEquals(expectedMap, dataFuture.join().values());
     }
 
     private static void updateConfig(ConfigurationRegistry registry, String 
updatedConfig) {
diff --git 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/util/ConfigurationUtilTest.java
 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/util/ConfigurationUtilTest.java
index 18fb0324b4a..2d2528ff6d7 100644
--- 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/util/ConfigurationUtilTest.java
+++ 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/util/ConfigurationUtilTest.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.configuration.util;
 
 import static java.util.Collections.emptyList;
+import static java.util.Collections.emptyNavigableMap;
 import static java.util.Collections.singletonMap;
 import static java.util.function.Function.identity;
 import static java.util.stream.Collectors.toList;
@@ -61,9 +62,11 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.NavigableMap;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.Spliterators;
+import java.util.TreeMap;
 import java.util.UUID;
 import java.util.function.Consumer;
 import java.util.stream.StreamSupport;
@@ -465,17 +468,19 @@ public class ConfigurationUtilTest {
                 Map.of(ParentConfiguration.KEY, 
newNodeInstance(ParentConfigurationSchema.class))
         );
 
-        assertThat(flattenedMap(superRoot, ParentConfiguration.KEY, node -> {
-        }), is(anEmptyMap()));
+        assertThat(flattenedMap(superRoot, ParentConfiguration.KEY, 
emptyNavigableMap(), node -> {}), is(anEmptyMap()));
 
-        assertThat(
-                flattenedMap(superRoot, ParentConfiguration.KEY, node -> 
((ParentChange) node)
+        Map<String, Serializable> flattenedMap =
+                flattenedMap(superRoot, ParentConfiguration.KEY, 
emptyNavigableMap(), node -> ((ParentChange) node)
                         .changeElements(elements -> elements
                                 .create("name", element -> element
                                         .changeChild(child -> 
child.changeStr("foo"))
                                 )
                         )
-                ),
+                );
+
+        assertThat(
+                flattenedMap,
                 is(allOf(
                         aMapWithSize(4),
                         
hasEntry(matchesPattern("root[.]elements[.]<ids>[.]name"), 
hasToString(matchesPattern("[-\\w]{36}"))),
@@ -486,14 +491,14 @@ public class ConfigurationUtilTest {
         );
 
         assertThat(
-                flattenedMap(superRoot, ParentConfiguration.KEY, node -> 
((ParentChange) node)
+                flattenedMap(superRoot, ParentConfiguration.KEY, new 
TreeMap<>(flattenedMap), node -> ((ParentChange) node)
                         .changeElements(elements1 -> elements1.delete("void"))
                 ),
                 is(anEmptyMap())
         );
 
         assertThat(
-                flattenedMap(superRoot, ParentConfiguration.KEY, node -> 
((ParentChange) node)
+                flattenedMap(superRoot, ParentConfiguration.KEY, new 
TreeMap<>(flattenedMap), node -> ((ParentChange) node)
                         .changeElements(elements -> elements.delete("name"))
                 ),
                 is(allOf(
@@ -1046,6 +1051,7 @@ public class ConfigurationUtilTest {
         final Map<String, Serializable> act = flattenedMap(
                 superRoot,
                 rootKey,
+                emptyNavigableMap(),
                 node -> ((PolymorphicRootChange) 
node).changePolymorphicSubCfg(c -> 
c.convert(SecondPolymorphicInstanceChange.class))
         );
 
@@ -1077,9 +1083,12 @@ public class ConfigurationUtilTest {
 
         SuperRoot superRoot = new SuperRoot(key -> null, Map.of(rootKey, 
polymorphicRootInnerNode));
 
-        final Map<String, Serializable> act = flattenedMap(
+        var storageData = new TreeMap<>(flattenedMap(superRoot, rootKey, 
emptyNavigableMap(), node -> {}));
+
+        Map<String, Serializable> act = flattenedMap(
                 superRoot,
                 rootKey,
+                storageData,
                 node -> ((PolymorphicRootChange) 
node).changePolymorphicNamedCfg(c ->
                         c.createOrUpdate("0", c1 -> 
c1.convert(SecondPolymorphicInstanceChange.class)))
         );
@@ -1174,12 +1183,14 @@ public class ConfigurationUtilTest {
      * method execution is completed.
      *
      * @param superRoot Super root to patch.
-     * @param patch     Closure to change inner node.
+     * @param storageData Full storage data.
+     * @param patch Closure to change inner node.
      * @return Flat map with all changes from the patch.
      */
-    private Map<String, Serializable> flattenedMap(
+    private static Map<String, Serializable> flattenedMap(
             SuperRoot superRoot,
             RootKey<?, ?> rootKey,
+            NavigableMap<String, ? extends Serializable> storageData,
             Consumer<InnerNode> patch
     ) {
         // Preserve a copy of the super root to use it as a golden source of 
data.
@@ -1192,7 +1203,7 @@ public class ConfigurationUtilTest {
         patch.accept(superRoot.getRoot(rootKey));
 
         // Create flat diff between two super trees.
-        return createFlattenedUpdatesMap(originalSuperRoot, superRoot, 
Map.of());
+        return createFlattenedUpdatesMap(originalSuperRoot, superRoot, 
storageData);
     }
 
     /**
diff --git 
a/modules/runner/src/main/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorage.java
 
b/modules/runner/src/main/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorage.java
index 120f63883b0..4e6c8a0748d 100644
--- 
a/modules/runner/src/main/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorage.java
+++ 
b/modules/runner/src/main/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorage.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.configuration.storage;
 
+import static java.util.Collections.emptyNavigableMap;
 import static java.util.stream.Collectors.toMap;
 import static 
org.apache.ignite.internal.configuration.util.ConfigurationFlattener.createFlattenedUpdatesMap;
 import static 
org.apache.ignite.internal.configuration.util.ConfigurationUtil.fillFromPrefixMap;
@@ -175,7 +176,7 @@ public class LocalFileConfigurationStorage implements 
ConfigurationStorage {
             Config hocon = readHoconFromFile();
             HoconConverter.hoconSource(hocon.root(), 
keyIgnorer).descend(copiedSuperRoot);
 
-            Map<String, Serializable> flattenedUpdatesMap = 
createFlattenedUpdatesMap(superRoot, copiedSuperRoot, Map.of());
+            Map<String, Serializable> flattenedUpdatesMap = 
createFlattenedUpdatesMap(superRoot, copiedSuperRoot, emptyNavigableMap());
             flattenedUpdatesMap.forEach((key, value) -> {
                 if (value != null) { // Filter defaults.
                     latest.put(key, value);

Reply via email to