This is an automated email from the ASF dual-hosted git repository. mpochatkin pushed a commit to branch IGNITE-26363 in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit d6a83d61860d79b11b3d43602f068d7de0985bbe Author: Pochatkin Mikhail <[email protected]> AuthorDate: Wed Oct 8 11:29:02 2025 +0300 IGNITE-26363 Node configuration validation on restart --- .../storage/DistributedConfigurationStorage.java | 15 ++-- .../storage/LocalFileConfigurationStorage.java | 91 ++++++++++++++-------- ...Storage.java => VaultConfigurationStorage.java} | 20 ++--- .../storage/ConfigurationStorageTest.java | 2 +- .../storage/LocalFileConfigurationStorageTest.java | 38 +++++++-- ...est.java => VaultConfigurationStorageTest.java} | 6 +- modules/configuration/build.gradle | 4 + .../configuration/ItNodeConfigurationTest.java | 12 +++ .../configuration/ConfigurationChanger.java | 72 +++++++---------- .../configuration/ConfigurationRegistry.java | 1 - .../configuration/ConfigurationUpdateListener.java | 23 ++++++ .../storage/ConfigurationStorage.java | 8 +- .../storage/ConfigurationStorageListener.java | 2 +- .../storage/{Data.java => ReadEntry.java} | 17 +++- .../internal/configuration/storage/WriteEntry.java | 12 +++ .../configuration/storage/WriteEntryImpl.java | 61 +++++++++++++++ .../configuration/ConfigurationChangerTest.java | 4 +- .../configuration/LocalFileConfigurationTest.java | 5 ++ .../configuration/RenamedConfigurationTest.java | 8 +- .../configuration/TestSubConfigurationSchema.java | 2 + .../deprecation/DeprecatedConfigurationTest.java | 20 ++--- .../configuration/tree/NamedListNodeTest.java | 16 ++-- .../storage/TestConfigurationStorage.java | 12 +-- modules/distribution-zones/build.gradle | 1 + ...niteDistributionZoneManagerNodeRestartTest.java | 3 +- .../rebalance/ItRebalanceDistributedTest.java | 3 +- modules/partition-replicator/build.gradle | 1 + .../partition/replicator/fixtures/Node.java | 3 +- modules/runner/build.gradle | 2 + .../configuration/generator/DefaultsGenerator.java | 11 ++- .../ItDistributedConfigurationStorageTest.java | 4 +- .../runner/app/ItIgniteNodeRestartTest.java | 3 +- .../org/apache/ignite/internal/app/IgniteImpl.java | 1 + 33 files changed, 335 insertions(+), 148 deletions(-) diff --git a/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/DistributedConfigurationStorage.java b/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/DistributedConfigurationStorage.java index 90c4b5d5c83..2fa676a2c0e 100644 --- a/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/DistributedConfigurationStorage.java +++ b/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/DistributedConfigurationStorage.java @@ -176,14 +176,14 @@ public class DistributedConfigurationStorage implements ConfigurationStorage { } @Override - public CompletableFuture<Data> readDataOnRecovery() throws StorageException { - CompletableFuture<Data> future = metaStorageMgr.recoveryFinishedFuture() + public CompletableFuture<ReadEntry> readDataOnRecovery() throws StorageException { + CompletableFuture<ReadEntry> future = metaStorageMgr.recoveryFinishedFuture() .thenApplyAsync(revisions -> readDataOnRecovery0(revisions.revision()), threadPool); return registerFuture(future); } - private Data readDataOnRecovery0(long metaStorageRevision) { + private ReadEntry readDataOnRecovery0(long metaStorageRevision) { Map<String, Serializable> data = new HashMap<>(); long cfgRevision = 0; @@ -221,12 +221,13 @@ public class DistributedConfigurationStorage implements ConfigurationStorage { changeId = cfgRevision; - return new Data(data, cfgRevision); + return new ReadEntry(data, cfgRevision); } /** {@inheritDoc} */ @Override - public CompletableFuture<Boolean> write(Map<String, ? extends Serializable> newValues, long curChangeId) { + public CompletableFuture<Boolean> write(WriteEntry writeEntry) { + long curChangeId = writeEntry.version(); assert curChangeId <= changeId; assert lsnr != null : "Configuration listener must be initialized before write."; @@ -239,7 +240,7 @@ public class DistributedConfigurationStorage implements ConfigurationStorage { var operations = new ArrayList<Operation>(); - for (Map.Entry<String, ? extends Serializable> entry : newValues.entrySet()) { + for (Map.Entry<String, ? extends Serializable> entry : writeEntry.newValues().entrySet()) { ByteArray key = new ByteArray(DISTRIBUTED_PREFIX + entry.getKey()); if (entry.getValue() != null) { @@ -297,7 +298,7 @@ public class DistributedConfigurationStorage implements ConfigurationStorage { changeId = newChangeId; - return lsnr.onEntriesChanged(new Data(data, newChangeId)); + return lsnr.onEntriesChanged(new ReadEntry(data, newChangeId)); }); } diff --git a/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorage.java b/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorage.java index 003c39e0caa..93d7657cd8d 100644 --- a/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorage.java +++ b/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorage.java @@ -24,7 +24,6 @@ import static org.apache.ignite.internal.configuration.util.ConfigurationFlatten import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.fillFromPrefixMap; import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.toPrefixMap; import static org.apache.ignite.internal.util.CompletableFutures.falseCompletedFuture; -import static org.apache.ignite.internal.util.CompletableFutures.trueCompletedFuture; import com.typesafe.config.Config; import com.typesafe.config.ConfigException.Parse; @@ -71,7 +70,10 @@ import org.apache.ignite.internal.future.InFlightFutures; import org.apache.ignite.internal.logger.IgniteLogger; import org.apache.ignite.internal.logger.Loggers; import org.apache.ignite.internal.thread.IgniteThreadFactory; +import org.apache.ignite.internal.util.CompletableFutures; import org.apache.ignite.internal.util.IgniteUtils; +import org.apache.ignite.internal.vault.VaultManager; +import org.apache.ignite.internal.vault.VaultService; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -108,6 +110,8 @@ public class LocalFileConfigurationStorage implements ConfigurationStorage { /** Tracks all running futures. */ private final InFlightFutures futureTracker = new InFlightFutures(); + private final VaultConfigurationStorage vaultStorage; + /** Last revision for configuration. */ private long lastRevision = 0L; @@ -119,8 +123,13 @@ public class LocalFileConfigurationStorage implements ConfigurationStorage { * @param module Configuration module, which provides configuration patches. */ @TestOnly - public LocalFileConfigurationStorage(Path configPath, ConfigurationTreeGenerator generator, @Nullable ConfigurationModule module) { - this("test", configPath, generator, module); + public LocalFileConfigurationStorage( + Path configPath, + ConfigurationTreeGenerator generator, + VaultService vaultService, + @Nullable ConfigurationModule module + ) { + this("test", configPath, generator, new VaultManager(vaultService), module); } /** @@ -131,11 +140,23 @@ public class LocalFileConfigurationStorage implements ConfigurationStorage { * @param module Configuration module, which provides configuration patches. */ public LocalFileConfigurationStorage( - String nodeName, Path configPath, ConfigurationTreeGenerator generator, @Nullable ConfigurationModule module) { + String nodeName, + Path configPath, + ConfigurationTreeGenerator generator, + VaultManager vaultManager, + @Nullable ConfigurationModule module + ) { this.configPath = configPath; this.generator = generator; this.tempConfigPath = configPath.resolveSibling(configPath.getFileName() + ".tmp"); this.module = module; + this.vaultStorage = new VaultConfigurationStorage(nodeName, vaultManager); + vaultStorage.registerConfigurationListener(new ConfigurationStorageListener() { + @Override + public CompletableFuture<Void> onEntriesChanged(ReadEntry changedEntries) { + return CompletableFutures.nullCompletedFuture(); + } + }); notificationsThreadPool = Executors.newFixedThreadPool( 2, IgniteThreadFactory.create(nodeName, "cfg-file", LOG) @@ -145,29 +166,31 @@ public class LocalFileConfigurationStorage implements ConfigurationStorage { } @Override - public CompletableFuture<Data> readDataOnRecovery() { + public CompletableFuture<ReadEntry> readDataOnRecovery() { lock.writeLock().lock(); try { - // Here we don't use ConfigurationDynamicDefaultsPatcher because it works only on Hocon string representation level. - // But it's not applicable here because we need to produce map presentation with same ids in names lists. - // Each tree walk for string to map mapping produce different ids by design. - String hocon = readHoconFromFile(); - SuperRoot superRoot = convertToSuperRoot(hocon); - - Map<String, Serializable> transformedHocon = transformToMap(superRoot); - - transformedHocon.forEach((key, value) -> { - if (value != null) { // Filter defaults. - latest.put(key, value); + return vaultStorage.readDataOnRecovery().thenApply(data -> { + // Here we don't use ConfigurationDynamicDefaultsPatcher because it works only on Hocon string representation level. + // But it's not applicable here because we need to produce map presentation with same ids in names lists. + // Each tree walk for string to map mapping produce different ids by design. + String hocon = readHoconFromFile(); + SuperRoot superRoot = convertToSuperRoot(hocon); + + Map<String, Serializable> transformedHocon = transformToMap(superRoot); + + transformedHocon.forEach((key, value) -> { + if (value != null) { // Filter defaults. + latest.put(key, value); + } + }); + + if (module != null) { + module.patchConfigurationWithDynamicDefaults(new SuperRootChangeImpl(superRoot)); + transformedHocon = transformToMap(superRoot); } - }); - if (module != null) { - module.patchConfigurationWithDynamicDefaults(new SuperRootChangeImpl(superRoot)); - transformedHocon = transformToMap(superRoot); - } - - return completedFuture(new Data(transformedHocon, lastRevision)); + return new ReadEntry(transformedHocon, lastRevision, data.values()); + }); } finally { lock.writeLock().unlock(); } @@ -241,18 +264,25 @@ public class LocalFileConfigurationStorage implements ConfigurationStorage { } @Override - public CompletableFuture<Boolean> write(Map<String, ? extends Serializable> newValues, long ver) { + public CompletableFuture<Boolean> write(WriteEntry writeEntry) { lock.writeLock().lock(); try { + long ver = writeEntry.version(); if (ver != lastRevision) { return falseCompletedFuture(); } - mergeAndSave(newValues); + return vaultStorage.write(writeEntry).thenApply(success -> { + if (!success) { + return false; + } - sendNotificationAsync(new Data(newValues, lastRevision)); + Map<String, ? extends Serializable> newValues = writeEntry.valuesWithFilteredDefaults(); + mergeAndSave(newValues); + sendNotificationAsync(new ReadEntry(newValues, lastRevision)); - return trueCompletedFuture(); + return true; + }); } finally { lock.writeLock().unlock(); } @@ -303,11 +333,6 @@ public class LocalFileConfigurationStorage implements ConfigurationStorage { IgniteUtils.shutdownAndAwaitTermination(notificationsThreadPool, 10, TimeUnit.SECONDS); } - @Override - public boolean supportDefaults() { - return false; - } - private void saveConfigFile() { if (!Files.isWritable(configPath)) { NodeConfigWriteException e = new NodeConfigWriteException( @@ -394,7 +419,7 @@ public class LocalFileConfigurationStorage implements ConfigurationStorage { } } - private void sendNotificationAsync(Data data) { + private void sendNotificationAsync(ReadEntry data) { CompletableFuture<Void> future = CompletableFuture.runAsync( () -> lsnrRef.get().onEntriesChanged(data), notificationsThreadPool diff --git a/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorage.java b/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/VaultConfigurationStorage.java similarity index 91% rename from modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorage.java rename to modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/VaultConfigurationStorage.java index edc73d925fc..0b89d4323ed 100644 --- a/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorage.java +++ b/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/VaultConfigurationStorage.java @@ -46,7 +46,7 @@ import org.apache.ignite.internal.vault.VaultManager; /** * Local configuration storage. */ -public class LocalConfigurationStorage implements ConfigurationStorage { +public class VaultConfigurationStorage implements ConfigurationStorage { /** Prefix that we add to configuration keys to distinguish them in the Vault. */ private static final String LOC_PREFIX = "loc-cfg."; @@ -54,7 +54,7 @@ public class LocalConfigurationStorage implements ConfigurationStorage { private static final ByteArray VERSION_KEY = new ByteArray(LOC_PREFIX + "$version"); /** Logger. */ - private static final IgniteLogger LOG = Loggers.forClass(LocalConfigurationStorage.class); + private static final IgniteLogger LOG = Loggers.forClass(VaultConfigurationStorage.class); /** Vault manager. */ private final VaultManager vaultMgr; @@ -89,7 +89,7 @@ public class LocalConfigurationStorage implements ConfigurationStorage { * * @param vaultMgr Vault manager. */ - public LocalConfigurationStorage(String nodeName, VaultManager vaultMgr) { + public VaultConfigurationStorage(String nodeName, VaultManager vaultMgr) { this.vaultMgr = vaultMgr; this.threadPool = Executors.newFixedThreadPool(4, IgniteThreadFactory.create(nodeName, "loc-cfg", LOG)); } @@ -108,7 +108,7 @@ public class LocalConfigurationStorage implements ConfigurationStorage { var rangeEnd = new ByteArray(incrementLastChar(LOC_PREFIX + prefix)); - return readAll(rangeStart, rangeEnd).thenApply(Data::values); + return readAll(rangeStart, rangeEnd).thenApply(ReadEntry::values); } /** {@inheritDoc} */ @@ -127,14 +127,14 @@ public class LocalConfigurationStorage implements ConfigurationStorage { /** {@inheritDoc} */ @Override - public CompletableFuture<Data> readDataOnRecovery() { + public CompletableFuture<ReadEntry> readDataOnRecovery() { return readAll(LOC_KEYS_START_RANGE, LOC_KEYS_END_RANGE); } /** * Retrieves all data, which keys lie in between {@code [rangeStart, rangeEnd)}. */ - private CompletableFuture<Data> readAll(ByteArray rangeStart, ByteArray rangeEnd) { + private CompletableFuture<ReadEntry> readAll(ByteArray rangeStart, ByteArray rangeEnd) { return registerFuture(supplyAsync(() -> { var data = new HashMap<String, Serializable>(); @@ -156,14 +156,16 @@ public class LocalConfigurationStorage implements ConfigurationStorage { throw new StorageException("Exception when closing a Vault cursor", e); } - return new Data(data, version); + return new ReadEntry(data, version); }, threadPool)); } /** {@inheritDoc} */ @Override - public CompletableFuture<Boolean> write(Map<String, ? extends Serializable> newValues, long sentVersion) { + public CompletableFuture<Boolean> write(WriteEntry writeEntry) { synchronized (writeSerializationLock) { + long sentVersion = writeEntry.version(); + Map<String, ? extends Serializable> newValues = writeEntry.newValues(); CompletableFuture<Boolean> writeFuture = registerFuture(writeSerializationFuture .thenCompose(v -> lastRevision()) .thenComposeAsync(version -> { @@ -192,7 +194,7 @@ public class LocalConfigurationStorage implements ConfigurationStorage { )); } - Data entries = new Data(newValues, version + 1); + ReadEntry entries = new ReadEntry(newValues, version + 1); vaultMgr.putAll(data); diff --git a/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageTest.java b/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageTest.java index 27005298691..b95bd9350dc 100644 --- a/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageTest.java +++ b/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageTest.java @@ -57,7 +57,7 @@ public abstract class ConfigurationStorageTest { public void testReadAllLatest() { var data = Map.of("foo1", "bar1", "foo2", "bar2"); - assertThat(storage.write(data, 0), willBe(equalTo(true))); + assertThat(storage.write(new WriteEntryImpl(data, 0)), willBe(equalTo(true))); // test that reading without a prefix retrieves all data CompletableFuture<Map<String, ? extends Serializable>> latestData = storage.readAllLatest(""); diff --git a/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorageTest.java b/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorageTest.java index 6d46b528df8..b1b6bea8a04 100644 --- a/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorageTest.java +++ b/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorageTest.java @@ -46,6 +46,7 @@ import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.ignite.configuration.ConfigurationChangeException; import org.apache.ignite.configuration.KeyIgnorer; import org.apache.ignite.configuration.annotation.Config; import org.apache.ignite.configuration.annotation.ConfigValue; @@ -58,6 +59,7 @@ 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.configuration.validation.ConfigurationValidationException; +import org.apache.ignite.configuration.validation.Immutable; import org.apache.ignite.internal.configuration.ConfigurationTreeGenerator; import org.apache.ignite.internal.configuration.TestConfigurationChanger; import org.apache.ignite.internal.configuration.hocon.HoconConverter; @@ -65,6 +67,7 @@ import org.apache.ignite.internal.configuration.tree.ConfigurationSource; import org.apache.ignite.internal.configuration.validation.ConfigurationValidatorImpl; import org.apache.ignite.internal.testframework.WorkDirectory; import org.apache.ignite.internal.testframework.WorkDirectoryExtension; +import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService; import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; @@ -110,7 +113,7 @@ public class LocalFileConfigurationStorageTest { @BeforeEach void before() { LocalFileConfigurationModule module = new LocalFileConfigurationModule(); - storage = new LocalFileConfigurationStorage(getConfigFile(), treeGenerator, module); + storage = new LocalFileConfigurationStorage(getConfigFile(), treeGenerator, new InMemoryVaultService(), module); changer = new TestConfigurationChanger( List.of(TopConfiguration.KEY), @@ -478,7 +481,7 @@ public class LocalFileConfigurationStorageTest { ConfigParseOptions parseOptions = ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON).setAllowMissing(false); assertDoesNotThrow(() -> ConfigFactory.parseFile(configFile.toFile(), parseOptions)); - LocalFileConfigurationStorage storage = new LocalFileConfigurationStorage(configFile, treeGenerator, null); + LocalFileConfigurationStorage storage = new LocalFileConfigurationStorage(configFile, treeGenerator, new InMemoryVaultService(), null); // And storage reads the file successfully assertDoesNotThrow(storage::readDataOnRecovery); @@ -507,7 +510,7 @@ public class LocalFileConfigurationStorageTest { // And storage detects duplicates assertThrows( - ConfigurationValidationException.class, + ConfigurationChangeException.class, changer::start, "Validation did not pass for keys: [top.inner.boolVal, Duplicated key]" ); @@ -551,8 +554,29 @@ public class LocalFileConfigurationStorageTest { assertFalse(Files.isWritable(configFile)); - var storage = new LocalFileConfigurationStorage(configFile, treeGenerator, new LocalFileConfigurationModule()); - assertThat(storage.write(Map.of(), storage.localRevision().get() + 1), willCompleteSuccessfully()); + var storage = new LocalFileConfigurationStorage( + configFile, + treeGenerator, + new InMemoryVaultService(), + new LocalFileConfigurationModule() + ); + assertThat(storage.write(new WriteEntryImpl(Map.of(), storage.localRevision().get() + 1)), willCompleteSuccessfully()); + } + + @Test + void test() throws Exception { + Path configFile = tmpDir.resolve(CONFIG_NAME + "test"); + File file = configFile.toFile(); + + assertFalse(Files.isWritable(configFile)); + + var storage = new LocalFileConfigurationStorage( + configFile, + treeGenerator, + new InMemoryVaultService(), + new LocalFileConfigurationModule() + ); + assertThat(storage.write(new WriteEntryImpl(Map.of(), storage.localRevision().get() + 1)), willCompleteSuccessfully()); } @Test @@ -604,6 +628,10 @@ public class LocalFileConfigurationStorageTest { @NamedConfigValue public PolyNamedListConfigurationSchema polyNamedList; + + @Immutable + @Value(hasDefault = true) + public int immutable = 0; } diff --git a/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorageTest.java b/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/VaultConfigurationStorageTest.java similarity index 91% rename from modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorageTest.java rename to modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/VaultConfigurationStorageTest.java index e68e597ac21..4fbcabf04ed 100644 --- a/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorageTest.java +++ b/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/VaultConfigurationStorageTest.java @@ -27,9 +27,9 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; /** - * Tests for the {@link LocalConfigurationStorage}. + * Tests for the {@link VaultConfigurationStorage}. */ -public class LocalConfigurationStorageTest extends ConfigurationStorageTest { +public class VaultConfigurationStorageTest extends ConfigurationStorageTest { private final VaultManager vaultManager = new VaultManager(new InMemoryVaultService()); /** @@ -51,6 +51,6 @@ public class LocalConfigurationStorageTest extends ConfigurationStorageTest { /** {@inheritDoc} */ @Override public ConfigurationStorage getStorage() { - return new LocalConfigurationStorage("test-node-name", vaultManager); + return new VaultConfigurationStorage("test-node-name", vaultManager); } } diff --git a/modules/configuration/build.gradle b/modules/configuration/build.gradle index f0f77c6676c..47c931a0195 100644 --- a/modules/configuration/build.gradle +++ b/modules/configuration/build.gradle @@ -19,6 +19,7 @@ apply from: "$rootDir/buildscripts/java-core.gradle" apply from: "$rootDir/buildscripts/publishing.gradle" apply from: "$rootDir/buildscripts/java-junit5.gradle" apply from: "$rootDir/buildscripts/java-test-fixtures.gradle" +apply from: "$rootDir/buildscripts/java-integration-test.gradle" description = 'ignite-configuration' @@ -39,4 +40,7 @@ dependencies { testFixturesImplementation project(':ignite-core') testFixturesImplementation testFixtures(project(':ignite-core')) testFixturesImplementation libs.typesafe.config + + integrationTestImplementation testFixtures(project(':ignite-core')) + integrationTestImplementation testFixtures(project(':ignite-runner')) } diff --git a/modules/configuration/src/integrationTest/java/org/apache/ignite/internal/configuration/ItNodeConfigurationTest.java b/modules/configuration/src/integrationTest/java/org/apache/ignite/internal/configuration/ItNodeConfigurationTest.java new file mode 100644 index 00000000000..0ba2414c47b --- /dev/null +++ b/modules/configuration/src/integrationTest/java/org/apache/ignite/internal/configuration/ItNodeConfigurationTest.java @@ -0,0 +1,12 @@ +package org.apache.ignite.internal.configuration; + +import org.apache.ignite.internal.ClusterPerClassIntegrationTest; +import org.junit.jupiter.api.Test; + +public class ItNodeConfigurationTest extends ClusterPerClassIntegrationTest { + + @Test + public void test() { + + } +} 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 e368a00ff29..6f38f2d5663 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 @@ -48,7 +48,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.NavigableMap; import java.util.NoSuchElementException; -import java.util.Objects; import java.util.RandomAccess; import java.util.StringJoiner; import java.util.TreeMap; @@ -69,7 +68,8 @@ import org.apache.ignite.configuration.validation.ValidationIssue; import org.apache.ignite.internal.configuration.direct.KeyPathNode; import org.apache.ignite.internal.configuration.storage.ConfigurationStorage; import org.apache.ignite.internal.configuration.storage.ConfigurationStorageListener; -import org.apache.ignite.internal.configuration.storage.Data; +import org.apache.ignite.internal.configuration.storage.ReadEntry; +import org.apache.ignite.internal.configuration.storage.WriteEntryImpl; import org.apache.ignite.internal.configuration.tree.ConfigurationSource; import org.apache.ignite.internal.configuration.tree.ConfigurationVisitor; import org.apache.ignite.internal.configuration.tree.ConstructableTreeNode; @@ -134,25 +134,6 @@ public abstract class ConfigurationChanger implements DynamicConfigurationChange /** Keys that were deleted from the configuration, but were present in the storage. Will be deleted on startup. */ private Collection<String> ignoredKeys; - /** - * Closure interface to be used by the configuration changer. An instance of this closure is passed into the constructor and invoked - * every time when there's an update from any of the storages. - */ - public interface ConfigurationUpdateListener { - /** - * Invoked every time when the configuration is updated. - * - * @param oldRoot Old roots values. All these roots always belong to a single storage. - * @param newRoot New values for the same roots as in {@code oldRoot}. - * @param storageRevision Configuration revision of the storage. - * @param notificationNumber Configuration listener notification number. - * @return Future that must signify when processing is completed. Exceptional completion is not expected. - */ - CompletableFuture<Void> onConfigurationUpdated( - @Nullable SuperRoot oldRoot, SuperRoot newRoot, long storageRevision, long notificationNumber - ); - } - /** * Immutable data container to store version and all roots associated with the specific storage. */ @@ -280,7 +261,7 @@ public abstract class ConfigurationChanger implements DynamicConfigurationChange * Start component. */ public void start() { - Data data; + ReadEntry data; try { data = storage.readDataOnRecovery().get(); @@ -292,7 +273,8 @@ public abstract class ConfigurationChanger implements DynamicConfigurationChange throw new ConfigurationChangeException("Failed to initialize configuration: " + e.getMessage(), e); } - var storageValues = new HashMap<String, Serializable>(data.values()); + Map<String, ? extends Serializable> values = data.values(); + var storageValues = new HashMap<String, Serializable>(values); ignoredKeys = ignoreDeleted(storageValues, keyIgnorer); @@ -324,15 +306,36 @@ public abstract class ConfigurationChanger implements DynamicConfigurationChange initialConfiguration.descend(superRoot); } - // Validate the restored configuration. - validateConfiguration(superRoot); + Map<String, ? extends Serializable> invariant = data.invariant(); + if (!invariant.isEmpty()) { + SuperRoot invariantRoot = new SuperRoot(rootCreator()); + Map<String, ?> invariantPrefixMap = toPrefixMap(invariant); + + for (RootKey<?, ?, ?> rootKey : rootKeys.values()) { + Map<String, ?> rootPrefixMap = (Map<String, ?>) invariantPrefixMap.get(rootKey.key()); + + InnerNode rootNode = createRootNode(rootKey); + + if (rootPrefixMap != null) { + fillFromPrefixMap(rootNode, rootPrefixMap); + } + + invariantRoot.addRoot(rootKey, rootNode); + } + + // Validate the restored configuration. + validateConfiguration(invariantRoot, superRoot); + } else { + validateConfiguration(superRoot); + } + // We store two configuration roots, one with the defaults set and another one without them. // The root WITH the defaults is used when we calculate who to notify of a configuration change or // when we provide the configuration outside. // 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.changeId(), new TreeMap<>(data.values())); + storageRoots = new StorageRoots(superRootNoDefaults, superRoot, data.changeId(), new TreeMap<>(values)); storage.registerConfigurationListener(configurationStorageListener()); @@ -676,17 +679,11 @@ public abstract class ConfigurationChanger implements DynamicConfigurationChange validateConfiguration(curRoots, changes); - // In some cases some storages may not want to persist configuration defaults. - // Need to filter it from change map before write to storage. - if (!storage.supportDefaults()) { - removeDefaultValues(allChanges); - } - // "allChanges" map can be empty here in case the given update matches the current state of the local configuration. We // 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.changeId) + return storage.write(new WriteEntryImpl(allChanges, defaultsMap.get(), localRoots.changeId)) .thenCompose(casWroteSuccessfully -> { if (casWroteSuccessfully) { return localRoots.changeFuture; @@ -798,15 +795,6 @@ public abstract class ConfigurationChanger implements DynamicConfigurationChange allChanges.entrySet().removeIf(entry -> entry.getValue() == null && !localRoots.storageData.containsKey(entry.getKey())); } - private void removeDefaultValues(Map<String, Serializable> allChanges) { - defaultsMap.get().forEach((key, defaultValue) -> { - Serializable change = allChanges.get(key); - if (Objects.deepEquals(change, defaultValue)) { - allChanges.put(key, null); - } - }); - } - private Map<String, Serializable> createDefaultsMap() { SuperRoot superRoot = new SuperRoot(rootCreator()); for (RootKey<?, ?, ?> rootKey : rootKeys.values()) { diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationRegistry.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationRegistry.java index c5a17433a52..445f34f6532 100644 --- a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationRegistry.java +++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationRegistry.java @@ -33,7 +33,6 @@ import org.apache.ignite.configuration.ConfigurationTree; import org.apache.ignite.configuration.KeyIgnorer; import org.apache.ignite.configuration.RootKey; import org.apache.ignite.configuration.SuperRootChange; -import org.apache.ignite.internal.configuration.ConfigurationChanger.ConfigurationUpdateListener; import org.apache.ignite.internal.configuration.storage.ConfigurationStorage; import org.apache.ignite.internal.configuration.tree.ConfigurationSource; import org.apache.ignite.internal.configuration.tree.ConfigurationVisitor; diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationUpdateListener.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationUpdateListener.java new file mode 100644 index 00000000000..bb6a72117cd --- /dev/null +++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationUpdateListener.java @@ -0,0 +1,23 @@ +package org.apache.ignite.internal.configuration; + +import java.util.concurrent.CompletableFuture; +import org.jetbrains.annotations.Nullable; + +/** + * Closure interface to be used by the configuration changer. An instance of this closure is passed into the constructor and invoked every + * time when there's an update from any of the storages. + */ +public interface ConfigurationUpdateListener { + /** + * Invoked every time when the configuration is updated. + * + * @param oldRoot Old roots values. All these roots always belong to a single storage. + * @param newRoot New values for the same roots as in {@code oldRoot}. + * @param storageRevision Configuration revision of the storage. + * @param notificationNumber Configuration listener notification number. + * @return Future that must signify when processing is completed. Exceptional completion is not expected. + */ + CompletableFuture<Void> onConfigurationUpdated( + @Nullable SuperRoot oldRoot, SuperRoot newRoot, long storageRevision, long notificationNumber + ); +} diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorage.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorage.java index b2a8da48b69..ff1ac34b000 100644 --- a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorage.java +++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorage.java @@ -32,7 +32,7 @@ public interface ConfigurationStorage extends ManuallyCloseable { * * @return Future that resolves into extracted values and version or a {@link StorageException} if the data could not be read. */ - CompletableFuture<Data> readDataOnRecovery(); + CompletableFuture<ReadEntry> readDataOnRecovery(); /** * Retrieves the most recent values which keys start with the given prefix, regardless of the current storage version. @@ -58,7 +58,7 @@ public interface ConfigurationStorage extends ManuallyCloseable { * @return Future that gives you {@code true} if successfully written, {@code false} if version of the storage is different from the * passed argument and {@link StorageException} if failed to write data. */ - CompletableFuture<Boolean> write(Map<String, ? extends Serializable> newValues, long ver); + CompletableFuture<Boolean> write(WriteEntry writeEntry); /** * Add listener to the storage that notifies of data changes. @@ -82,10 +82,6 @@ public interface ConfigurationStorage extends ManuallyCloseable { /** Returns a future that will be completed with the latest revision of the configuration storage. */ CompletableFuture<Long> localRevision(); - default boolean supportDefaults() { - return true; - } - /** * Closes the storage. */ diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageListener.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageListener.java index 928050e9c1f..42716ba3fc1 100644 --- a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageListener.java +++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageListener.java @@ -30,5 +30,5 @@ public interface ConfigurationStorageListener { * @param changedEntries Changed entries, key-value pairs and new version of the storage. * @return Completable future that signifies the completion of all custom user listeners execution. */ - CompletableFuture<Void> onEntriesChanged(Data changedEntries); + CompletableFuture<Void> onEntriesChanged(ReadEntry changedEntries); } diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/Data.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ReadEntry.java similarity index 74% rename from modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/Data.java rename to modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ReadEntry.java index 685e7e19b6e..5debc55e7b0 100644 --- a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/Data.java +++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ReadEntry.java @@ -24,10 +24,12 @@ import java.util.Map; /** * Represents data in configuration storage. */ -public class Data { +public class ReadEntry { /** Values. */ private final Map<String, ? extends Serializable> values; + private final Map<String, ? extends Serializable> invariant; + /** Configuration storage version. */ private final long changeId; @@ -37,9 +39,16 @@ public class Data { * @param values Values. * @param changeId Version. */ - public Data(Map<String, ? extends Serializable> values, long changeId) { + public ReadEntry(Map<String, ? extends Serializable> values, long changeId) { this.values = Collections.unmodifiableMap(values); this.changeId = changeId; + this.invariant = Collections.emptyMap(); + } + + public ReadEntry(Map<String, ? extends Serializable> values, long changeId, Map<String, ? extends Serializable> invariant) { + this.values = values; + this.changeId = changeId; + this.invariant = invariant; } /** Get values. */ @@ -47,6 +56,10 @@ public class Data { return values; } + public Map<String, ? extends Serializable> invariant() { + return invariant; + } + /** * Get version. * diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/WriteEntry.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/WriteEntry.java new file mode 100644 index 00000000000..901a7512cf3 --- /dev/null +++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/WriteEntry.java @@ -0,0 +1,12 @@ +package org.apache.ignite.internal.configuration.storage; + +import java.io.Serializable; +import java.util.Map; + +public interface WriteEntry { + Map<String, ? extends Serializable> newValues(); + + Map<String, ? extends Serializable> valuesWithFilteredDefaults(); + + long version(); +} diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/WriteEntryImpl.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/WriteEntryImpl.java new file mode 100644 index 00000000000..dbb3a9990df --- /dev/null +++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/WriteEntryImpl.java @@ -0,0 +1,61 @@ +package org.apache.ignite.internal.configuration.storage; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.apache.ignite.internal.util.Lazy; + +public class WriteEntryImpl implements WriteEntry { + private final Map<String, ? extends Serializable> defaults; + + private final Map<String, ? extends Serializable> allChanges; + + private final Lazy<Map<String, ? extends Serializable>> filtered = new Lazy<>(this::filteredDefaults); + + private final long version; + + public WriteEntryImpl( + Map<String, ? extends Serializable> changes, + long version + ) { + this(changes, Map.of(), version); + } + + public WriteEntryImpl( + Map<String, ? extends Serializable> allChanges, + Map<String, ? extends Serializable> defaults, + long version + ) { + this.defaults = defaults; + this.allChanges = allChanges; + this.version = version; + } + + @Override + public Map<String, ? extends Serializable> newValues() { + return Collections.unmodifiableMap(allChanges); + } + + @Override + public Map<String, ? extends Serializable> valuesWithFilteredDefaults() { + return filtered.get(); + } + + @Override + public long version() { + return version; + } + + private Map<String, ? extends Serializable> filteredDefaults() { + Map<String, ? extends Serializable> result = new HashMap<>(allChanges); + defaults.forEach((key, defaultValue) -> { + Serializable change = result.get(key); + if (Objects.deepEquals(change, defaultValue)) { + result.put(key, null); + } + }); + return result; + } +} diff --git a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/ConfigurationChangerTest.java b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/ConfigurationChangerTest.java index 41f00cfe175..fe5ecd93867 100644 --- a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/ConfigurationChangerTest.java +++ b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/ConfigurationChangerTest.java @@ -62,7 +62,7 @@ import org.apache.ignite.configuration.validation.Validator; import org.apache.ignite.internal.configuration.direct.KeyPathNode; import org.apache.ignite.internal.configuration.hocon.HoconConverter; import org.apache.ignite.internal.configuration.storage.ConfigurationStorage; -import org.apache.ignite.internal.configuration.storage.Data; +import org.apache.ignite.internal.configuration.storage.ReadEntry; import org.apache.ignite.internal.configuration.storage.TestConfigurationStorage; import org.apache.ignite.internal.configuration.tree.ConfigurationSource; import org.apache.ignite.internal.configuration.tree.ConstructableTreeNode; @@ -274,7 +274,7 @@ public class ConfigurationChangerTest { storage.fail(false); - CompletableFuture<Map<String, ? extends Serializable>> dataFuture = storage.readDataOnRecovery().thenApply(Data::values); + CompletableFuture<Map<String, ? extends Serializable>> dataFuture = storage.readDataOnRecovery().thenApply(ReadEntry::values); assertThat(dataFuture, willCompleteSuccessfully()); diff --git a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/LocalFileConfigurationTest.java b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/LocalFileConfigurationTest.java new file mode 100644 index 00000000000..88e0dad3457 --- /dev/null +++ b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/LocalFileConfigurationTest.java @@ -0,0 +1,5 @@ +package org.apache.ignite.internal.configuration; + +public class LocalFileConfigurationTest { + private final +} 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 6ec3abb5884..140c6668ac5 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 @@ -48,7 +48,7 @@ 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.storage.Data; +import org.apache.ignite.internal.configuration.storage.ReadEntry; import org.apache.ignite.internal.configuration.storage.TestConfigurationStorage; import org.apache.ignite.internal.configuration.util.ConfigurationUtil; import org.apache.ignite.internal.configuration.validation.TestConfigurationValidator; @@ -272,7 +272,7 @@ class RenamedConfigurationTest extends BaseIgniteAbstractTest { */ @SafeVarargs private void validateStorageContent(Map.Entry<String, Serializable> ...values) { - CompletableFuture<Data> dataFuture = storage.readDataOnRecovery(); + CompletableFuture<ReadEntry> dataFuture = storage.readDataOnRecovery(); assertThat(dataFuture, willCompleteSuccessfully()); RenamedTestNewView node = registry.getConfiguration(RenamedTestNewConfiguration.KEY).value(); @@ -318,8 +318,8 @@ class RenamedConfigurationTest extends BaseIgniteAbstractTest { storage.close(); } - private Data getData() { - CompletableFuture<Data> dataFuture = storage.readDataOnRecovery(); + private ReadEntry getData() { + CompletableFuture<ReadEntry> dataFuture = storage.readDataOnRecovery(); assertThat(dataFuture, willCompleteSuccessfully()); diff --git a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/TestSubConfigurationSchema.java b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/TestSubConfigurationSchema.java index 5f2287a24e5..6d5cd9a3dc5 100644 --- a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/TestSubConfigurationSchema.java +++ b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/TestSubConfigurationSchema.java @@ -35,4 +35,6 @@ public class TestSubConfigurationSchema { @Value(hasDefault = true) public int testInt; + + } diff --git a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/deprecation/DeprecatedConfigurationTest.java b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/deprecation/DeprecatedConfigurationTest.java index 4f0e9c63b08..8f793a93b68 100644 --- a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/deprecation/DeprecatedConfigurationTest.java +++ b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/deprecation/DeprecatedConfigurationTest.java @@ -49,7 +49,7 @@ import org.apache.ignite.internal.configuration.SuperRoot; import org.apache.ignite.internal.configuration.SuperRootChangeImpl; import org.apache.ignite.internal.configuration.TestConfigurationChanger; import org.apache.ignite.internal.configuration.storage.ConfigurationStorage; -import org.apache.ignite.internal.configuration.storage.Data; +import org.apache.ignite.internal.configuration.storage.ReadEntry; import org.apache.ignite.internal.configuration.storage.TestConfigurationStorage; import org.apache.ignite.internal.configuration.tree.ConfigurationSource; import org.apache.ignite.internal.configuration.tree.ConstructableTreeNode; @@ -197,7 +197,7 @@ public class DeprecatedConfigurationTest extends BaseIgniteAbstractTest { lastWriteCapture.getValue() ); - Data data = getData(); + ReadEntry data = getData(); assertEquals(1, data.changeId()); assertEquals( @@ -227,7 +227,7 @@ public class DeprecatedConfigurationTest extends BaseIgniteAbstractTest { ); // Check that deprecated value is not present in the storage anymore. - Data data = getData(); + ReadEntry data = getData(); assertEquals(2, data.changeId()); assertEquals( Map.of("root.child.my-int-cfg", 99), @@ -315,7 +315,7 @@ public class DeprecatedConfigurationTest extends BaseIgniteAbstractTest { ); // Check that deprecated value is not present in the storage anymore. - Data data = getData(); + ReadEntry data = getData(); assertEquals(2, data.changeId()); assertEquals( @@ -370,7 +370,7 @@ public class DeprecatedConfigurationTest extends BaseIgniteAbstractTest { ); // Check storage state. - Data data = getData(); + ReadEntry data = getData(); assertEquals(2, data.changeId()); assertEquals( @@ -403,7 +403,7 @@ public class DeprecatedConfigurationTest extends BaseIgniteAbstractTest { ); // Check that deprecated value is not present in the storage anymore. - Data data = getData(); + ReadEntry data = getData(); assertEquals(3, data.changeId()); assertEquals( @@ -467,7 +467,7 @@ public class DeprecatedConfigurationTest extends BaseIgniteAbstractTest { ); // Check storage state. - Data data = getData(); + ReadEntry data = getData(); assertEquals(2, data.changeId()); assertEquals( @@ -502,7 +502,7 @@ public class DeprecatedConfigurationTest extends BaseIgniteAbstractTest { ); // Check that deprecated value is not present in the storage anymore. - Data data = getData(); + ReadEntry data = getData(); assertEquals(3, data.changeId()); assertEquals( @@ -557,8 +557,8 @@ public class DeprecatedConfigurationTest extends BaseIgniteAbstractTest { assertThat(changeFuture, willCompleteSuccessfully()); } - private Data getData() { - CompletableFuture<Data> dataFuture = storage.readDataOnRecovery(); + private ReadEntry getData() { + CompletableFuture<ReadEntry> dataFuture = storage.readDataOnRecovery(); assertThat(dataFuture, willCompleteSuccessfully()); diff --git a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/tree/NamedListNodeTest.java b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/tree/NamedListNodeTest.java index 7c334618a5f..aaed6127bcf 100644 --- a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/tree/NamedListNodeTest.java +++ b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/tree/NamedListNodeTest.java @@ -39,7 +39,7 @@ import org.apache.ignite.configuration.annotation.NamedConfigValue; import org.apache.ignite.configuration.annotation.Value; import org.apache.ignite.internal.configuration.ConfigurationTreeGenerator; import org.apache.ignite.internal.configuration.TestConfigurationChanger; -import org.apache.ignite.internal.configuration.storage.Data; +import org.apache.ignite.internal.configuration.storage.ReadEntry; import org.apache.ignite.internal.configuration.storage.TestConfigurationStorage; import org.apache.ignite.internal.configuration.util.ConfigurationUtil; import org.apache.ignite.internal.configuration.validation.TestConfigurationValidator; @@ -140,7 +140,7 @@ public class NamedListNodeTest { UUID x0Id = ((NamedListNode<?>) a.second().value()).internalId("X"); UUID z0Id = ((NamedListNode<?>) a.second().get("X").third().value()).internalId("Z0"); - CompletableFuture<Map<String, ? extends Serializable>> storageValues = storage.readDataOnRecovery().thenApply(Data::values); + CompletableFuture<Map<String, ? extends Serializable>> storageValues = storage.readDataOnRecovery().thenApply(ReadEntry::values); assertThat( storageValues, @@ -164,7 +164,7 @@ public class NamedListNodeTest { UUID z5Id = ((NamedListNode<?>) a.second().get("X").third().value()).internalId("Z5"); - storageValues = storage.readDataOnRecovery().thenApply(Data::values); + storageValues = storage.readDataOnRecovery().thenApply(ReadEntry::values); assertThat( storageValues, @@ -190,7 +190,7 @@ public class NamedListNodeTest { UUID z2Id = ((NamedListNode<?>) a.second().get("X").third().value()).internalId("Z2"); - storageValues = storage.readDataOnRecovery().thenApply(Data::values); + storageValues = storage.readDataOnRecovery().thenApply(ReadEntry::values); assertThat( storageValues, @@ -220,7 +220,7 @@ public class NamedListNodeTest { UUID z3Id = ((NamedListNode<?>) a.second().get("X").third().value()).internalId("Z3"); - storageValues = storage.readDataOnRecovery().thenApply(Data::values); + storageValues = storage.readDataOnRecovery().thenApply(ReadEntry::values); assertThat( storageValues, @@ -252,7 +252,7 @@ public class NamedListNodeTest { // Delete keys from the middle. Indexes of Z3 should be updated to 1. x.third().change(xb -> xb.delete("Z2").delete("Z5")).get(); - storageValues = storage.readDataOnRecovery().thenApply(Data::values); + storageValues = storage.readDataOnRecovery().thenApply(ReadEntry::values); assertThat( storageValues, @@ -276,7 +276,7 @@ public class NamedListNodeTest { // Delete keys from the middle. Indexes of Z3 should be updated to 1. x.third().change(xb -> xb.rename("Z0", "Z1")).get(); - storageValues = storage.readDataOnRecovery().thenApply(Data::values); + storageValues = storage.readDataOnRecovery().thenApply(ReadEntry::values); assertThat( storageValues, @@ -300,7 +300,7 @@ public class NamedListNodeTest { // Delete values on several layers simultaneously. Storage must be empty after that. a.second().change(b -> b.delete("X")).get(); - assertThat(storage.readDataOnRecovery().thenApply(Data::values), willBe(anEmptyMap())); + assertThat(storage.readDataOnRecovery().thenApply(ReadEntry::values), willBe(anEmptyMap())); } /** Tests exceptions described in methods signatures. */ diff --git a/modules/configuration/src/testFixtures/java/org/apache/ignite/internal/configuration/storage/TestConfigurationStorage.java b/modules/configuration/src/testFixtures/java/org/apache/ignite/internal/configuration/storage/TestConfigurationStorage.java index 7bd50a019a9..bf4a2a5a372 100644 --- a/modules/configuration/src/testFixtures/java/org/apache/ignite/internal/configuration/storage/TestConfigurationStorage.java +++ b/modules/configuration/src/testFixtures/java/org/apache/ignite/internal/configuration/storage/TestConfigurationStorage.java @@ -108,32 +108,32 @@ public class TestConfigurationStorage implements ConfigurationStorage { /** {@inheritDoc} */ @Override - public CompletableFuture<Data> readDataOnRecovery() { + public CompletableFuture<ReadEntry> readDataOnRecovery() { return supplyAsync(() -> { synchronized (this) { if (fail) { throw new StorageException("Failed to read data"); } - return new Data(new HashMap<>(map), version); + return new ReadEntry(new HashMap<>(map), version); } }); } /** {@inheritDoc} */ @Override - public CompletableFuture<Boolean> write(Map<String, ? extends Serializable> newValues, long sentVersion) { + public CompletableFuture<Boolean> write(WriteEntry writeEntry) { return supplyAsync(() -> { synchronized (this) { if (fail) { throw new StorageException("Failed to write data"); } - if (sentVersion != version) { + if (writeEntry.version() != version) { return false; } - for (Map.Entry<String, ? extends Serializable> entry : newValues.entrySet()) { + for (Map.Entry<String, ? extends Serializable> entry : writeEntry.newValues().entrySet()) { if (entry.getValue() != null) { map.put(entry.getKey(), entry.getValue()); } else { @@ -143,7 +143,7 @@ public class TestConfigurationStorage implements ConfigurationStorage { version++; - var data = new Data(newValues, version); + var data = new ReadEntry(writeEntry.newValues(), version); listeners.forEach(listener -> listener.onEntriesChanged(data).join()); diff --git a/modules/distribution-zones/build.gradle b/modules/distribution-zones/build.gradle index 1d6bc17185e..7f4aa5535ea 100644 --- a/modules/distribution-zones/build.gradle +++ b/modules/distribution-zones/build.gradle @@ -129,6 +129,7 @@ dependencies { integrationTestImplementation testFixtures(project(':ignite-transactions')) integrationTestImplementation testFixtures(project(':ignite-sql-engine')) integrationTestImplementation testFixtures(project(':ignite-configuration-system')) + integrationTestImplementation testFixtures(project(':ignite-vault')) } diff --git a/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/distributionzones/ItIgniteDistributionZoneManagerNodeRestartTest.java b/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/distributionzones/ItIgniteDistributionZoneManagerNodeRestartTest.java index 3673a1138f9..84e7cf7019a 100644 --- a/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/distributionzones/ItIgniteDistributionZoneManagerNodeRestartTest.java +++ b/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/distributionzones/ItIgniteDistributionZoneManagerNodeRestartTest.java @@ -130,6 +130,7 @@ import org.apache.ignite.internal.testframework.ExecutorServiceExtension; import org.apache.ignite.internal.testframework.InjectExecutorService; import org.apache.ignite.internal.testframework.TestIgnitionManager; import org.apache.ignite.internal.vault.VaultManager; +import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService; import org.apache.ignite.internal.version.DefaultIgniteProductVersionSource; import org.apache.ignite.internal.worker.fixtures.NoOpCriticalWorkerRegistry; import org.apache.ignite.network.NetworkAddress; @@ -218,7 +219,7 @@ public class ItIgniteDistributionZoneManagerNodeRestartTest extends BaseIgniteRe var nodeCfgMgr = new ConfigurationManager( modules.local().rootKeys(), - new LocalFileConfigurationStorage(configFile, localConfigurationGenerator, modules.local()), + new LocalFileConfigurationStorage(configFile, localConfigurationGenerator, new InMemoryVaultService(), modules.local()), localConfigurationGenerator, ConfigurationValidatorImpl.withDefaultValidators(localConfigurationGenerator, modules.local().validators()) ); diff --git a/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/rebalance/ItRebalanceDistributedTest.java b/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/rebalance/ItRebalanceDistributedTest.java index 80f853be282..91ff99d20ea 100644 --- a/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/rebalance/ItRebalanceDistributedTest.java +++ b/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/rebalance/ItRebalanceDistributedTest.java @@ -270,6 +270,7 @@ import org.apache.ignite.internal.tx.storage.state.rocksdb.TxStateRocksDbSharedS import org.apache.ignite.internal.tx.storage.state.test.TestTxStateStorage; import org.apache.ignite.internal.tx.test.TestLocalRwTxCounter; import org.apache.ignite.internal.vault.VaultManager; +import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService; import org.apache.ignite.internal.vault.persistence.PersistentVaultService; import org.apache.ignite.network.NetworkAddress; import org.apache.ignite.raft.jraft.rpc.CliRequests.ChangePeersAndLearnersAsyncRequest; @@ -1296,7 +1297,7 @@ public class ItRebalanceDistributedTest extends BaseIgniteAbstractTest { nodeCfgMgr = new ConfigurationManager( List.of(NodeConfiguration.KEY), - new LocalFileConfigurationStorage(configPath, nodeCfgGenerator, null), + new LocalFileConfigurationStorage(configPath, nodeCfgGenerator, new InMemoryVaultService(), null), nodeCfgGenerator, new TestConfigurationValidator() ); diff --git a/modules/partition-replicator/build.gradle b/modules/partition-replicator/build.gradle index 5d725fa9611..8fd2503557f 100644 --- a/modules/partition-replicator/build.gradle +++ b/modules/partition-replicator/build.gradle @@ -71,6 +71,7 @@ dependencies { integrationTestImplementation testFixtures(project(':ignite-storage-api')) integrationTestImplementation testFixtures(project(':ignite-table')) integrationTestImplementation testFixtures(project(':ignite-transactions')) + integrationTestImplementation testFixtures(project(':ignite-vault')) integrationTestImplementation project(':ignite-raft') integrationTestImplementation project(':ignite-raft-api') diff --git a/modules/partition-replicator/src/integrationTest/java/org/apache/ignite/internal/partition/replicator/fixtures/Node.java b/modules/partition-replicator/src/integrationTest/java/org/apache/ignite/internal/partition/replicator/fixtures/Node.java index e8c616a44dd..359e8296f40 100644 --- a/modules/partition-replicator/src/integrationTest/java/org/apache/ignite/internal/partition/replicator/fixtures/Node.java +++ b/modules/partition-replicator/src/integrationTest/java/org/apache/ignite/internal/partition/replicator/fixtures/Node.java @@ -195,6 +195,7 @@ import org.apache.ignite.internal.tx.storage.state.TxStateStorage; import org.apache.ignite.internal.tx.storage.state.rocksdb.TxStateRocksDbSharedStorage; import org.apache.ignite.internal.tx.test.TestLocalRwTxCounter; import org.apache.ignite.internal.vault.VaultManager; +import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService; import org.apache.ignite.network.NetworkAddress; import org.apache.ignite.raft.jraft.rpc.impl.RaftGroupEventsClientListener; import org.apache.ignite.sql.IgniteSql; @@ -370,7 +371,7 @@ public class Node { nodeCfgMgr = new ConfigurationManager( List.of(NodeConfiguration.KEY), - new LocalFileConfigurationStorage(configPath, nodeCfgGenerator, null), + new LocalFileConfigurationStorage(configPath, nodeCfgGenerator, new InMemoryVaultService(), null), nodeCfgGenerator, new TestConfigurationValidator() ); diff --git a/modules/runner/build.gradle b/modules/runner/build.gradle index b7edce5679a..0c88a8226f9 100644 --- a/modules/runner/build.gradle +++ b/modules/runner/build.gradle @@ -109,6 +109,8 @@ dependencies { testAnnotationProcessor project(':ignite-configuration-annotation-processor') testAnnotationProcessor libs.auto.service + defaultsGeneratorImplementation testFixtures(project(':ignite-vault')) + testImplementation project(':ignite-cluster-management') testImplementation project(':ignite-configuration') testImplementation project(':ignite-core') diff --git a/modules/runner/src/defaultsGenerator/java/org/apache/ignite/internal/configuration/generator/DefaultsGenerator.java b/modules/runner/src/defaultsGenerator/java/org/apache/ignite/internal/configuration/generator/DefaultsGenerator.java index 332e5575254..a3bfbec4c56 100644 --- a/modules/runner/src/defaultsGenerator/java/org/apache/ignite/internal/configuration/generator/DefaultsGenerator.java +++ b/modules/runner/src/defaultsGenerator/java/org/apache/ignite/internal/configuration/generator/DefaultsGenerator.java @@ -28,7 +28,7 @@ import org.apache.ignite.configuration.KeyIgnorer; import org.apache.ignite.configuration.RootKey; import org.apache.ignite.configuration.annotation.ConfigurationType; import org.apache.ignite.internal.configuration.ConfigurationChanger; -import org.apache.ignite.internal.configuration.ConfigurationChanger.ConfigurationUpdateListener; +import org.apache.ignite.internal.configuration.ConfigurationUpdateListener; import org.apache.ignite.internal.configuration.ConfigurationModules; import org.apache.ignite.internal.configuration.ConfigurationTreeGenerator; import org.apache.ignite.internal.configuration.ServiceLoaderModulesProvider; @@ -37,6 +37,8 @@ import org.apache.ignite.internal.configuration.storage.LocalFileConfigurationSt import org.apache.ignite.internal.configuration.tree.InnerNode; import org.apache.ignite.internal.configuration.validation.ConfigurationValidator; import org.apache.ignite.internal.configuration.validation.ConfigurationValidatorImpl; +import org.apache.ignite.internal.vault.VaultManager; +import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService; import org.jetbrains.annotations.Nullable; /** @@ -89,7 +91,12 @@ public class DefaultsGenerator { ); ConfigurationStorage storage = new LocalFileConfigurationStorage( - "defaultGen", configPath, localConfigurationGenerator, modules.local()); + "defaultGen", + configPath, + localConfigurationGenerator, + new VaultManager(new InMemoryVaultService()), + modules.local() + ); ConfigurationValidator configurationValidator = ConfigurationValidatorImpl.withDefaultValidators(localConfigurationGenerator, modules.local().validators()); diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/configuration/storage/ItDistributedConfigurationStorageTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/configuration/storage/ItDistributedConfigurationStorageTest.java index 765daea938c..24c6bff6587 100644 --- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/configuration/storage/ItDistributedConfigurationStorageTest.java +++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/configuration/storage/ItDistributedConfigurationStorageTest.java @@ -341,9 +341,9 @@ public class ItDistributedConfigurationStorageTest extends BaseIgniteAbstractTes node2.waitWatches(); - CompletableFuture<Data> storageData = node2.cfgStorage.readDataOnRecovery(); + CompletableFuture<ReadEntry> storageData = node2.cfgStorage.readDataOnRecovery(); - assertThat(storageData.thenApply(Data::values), willBe(equalTo(data))); + assertThat(storageData.thenApply(ReadEntry::values), willBe(equalTo(data))); } finally { node2.stop(); } diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java index 6f3454d6d65..b3ea7d3f894 100644 --- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java +++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java @@ -236,6 +236,7 @@ import org.apache.ignite.internal.tx.test.TestLocalRwTxCounter; import org.apache.ignite.internal.util.ByteUtils; import org.apache.ignite.internal.util.Cursor; import org.apache.ignite.internal.vault.VaultManager; +import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService; import org.apache.ignite.internal.version.DefaultIgniteProductVersionSource; import org.apache.ignite.internal.worker.CriticalWorkerWatchdog; import org.apache.ignite.internal.worker.configuration.CriticalWorkersConfiguration; @@ -373,7 +374,7 @@ public class ItIgniteNodeRestartTest extends BaseIgniteRestartTest { var nodeCfgMgr = new ConfigurationManager( modules.local().rootKeys(), - new LocalFileConfigurationStorage(configFile, localConfigurationGenerator, modules.local()), + new LocalFileConfigurationStorage(configFile, localConfigurationGenerator, new InMemoryVaultService(), modules.local()), localConfigurationGenerator, ConfigurationValidatorImpl.withDefaultValidators(localConfigurationGenerator, modules.local().validators()) ); diff --git a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java index f318532845d..db5c74b21e6 100644 --- a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java +++ b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java @@ -557,6 +557,7 @@ public class IgniteImpl implements Ignite { name, configPath, localConfigurationGenerator, + vaultMgr, modules.local() );
