This is an automated email from the ASF dual-hosted git repository.
sk0x50 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 6f3c9a0fc2 IGNITE-18093 Introduced distribution zone manager for the
purposes of zones configuration. Fixes #1339
6f3c9a0fc2 is described below
commit 6f3c9a0fc2fc4bd6f8263416305f0f9724e7e4be
Author: Sergey Uttsel <[email protected]>
AuthorDate: Mon Nov 28 09:50:00 2022 +0200
IGNITE-18093 Introduced distribution zone manager for the purposes of zones
configuration. Fixes #1339
Signed-off-by: Slava Koptilin <[email protected]>
---
.../ignite/configuration/NamedListChange.java | 5 +-
.../internal/configuration/tree/NamedListNode.java | 4 +
.../java/org/apache/ignite/lang/ErrorGroups.java | 15 +
modules/distribution-zones/build.gradle | 42 ++
modules/distribution-zones/pom.xml | 135 +++++++
.../DistributionZoneConfigurationParameters.java | 179 +++++++++
.../distributionzones/DistributionZoneManager.java | 208 ++++++++++
.../DistributionZoneConfigurationSchema.java | 55 +++
.../DistributionZonesConfigurationSchema.java | 37 ++
.../DistributionZoneAlreadyExistsException.java | 51 +++
.../DistributionZoneNotFoundException.java | 60 +++
.../exception/DistributionZoneRenameException.java | 51 +++
...istributionZoneConfigurationParametersTest.java | 106 +++++
.../DistributionZoneManagerTest.java | 442 +++++++++++++++++++++
.../ErrorGroupsGenerator.cs | 2 +-
.../dotnet/Apache.Ignite.Tests/ErrorGroupTests.cs | 4 +
modules/runner/build.gradle | 1 +
modules/runner/pom.xml | 5 +
.../org/apache/ignite/internal/app/IgniteImpl.java | 15 +
parent/pom.xml | 6 +
pom.xml | 1 +
settings.gradle | 2 +
22 files changed, 1423 insertions(+), 3 deletions(-)
diff --git
a/modules/configuration-api/src/main/java/org/apache/ignite/configuration/NamedListChange.java
b/modules/configuration-api/src/main/java/org/apache/ignite/configuration/NamedListChange.java
index c4e1865b90..912a56572a 100644
---
a/modules/configuration-api/src/main/java/org/apache/ignite/configuration/NamedListChange.java
+++
b/modules/configuration-api/src/main/java/org/apache/ignite/configuration/NamedListChange.java
@@ -99,8 +99,9 @@ public interface NamedListChange<VIEWT, CHANGET extends
VIEWT> extends NamedList
NamedListChange<VIEWT, CHANGET> update(String key, Consumer<CHANGET>
valConsumer);
/**
- * Renames the existing value in the named list configuration. Element
with key {@code oldKey} must exist and key
- * {@code newKey} must not. Error will occur if {@code newKey} has just
been deleted on the same
+ * Renames the existing value in the named list configuration. Does
nothing if {@code oldKey} and {@code newKey} are the same.
+ * Element with key {@code oldKey} must exist and key {@code newKey} must
not.
+ * Error will occur if {@code newKey} has just been deleted on the same
* {@link NamedListChange} instance (to distinguish between
* {@link ConfigurationNamedListListener#onRename(String, String,
ConfigurationNotificationEvent)} and
* {@link
ConfigurationNamedListListener#onUpdate(ConfigurationNotificationEvent)} on
{@code newKey}).
diff --git
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/tree/NamedListNode.java
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/tree/NamedListNode.java
index da94ba0a92..694c7208d0 100644
---
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/tree/NamedListNode.java
+++
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/tree/NamedListNode.java
@@ -271,6 +271,10 @@ public final class NamedListNode<N> implements
NamedListChange<N, N>, Traversabl
Objects.requireNonNull(oldKey, "oldKey");
Objects.requireNonNull(newKey, "newKey");
+ if (oldKey.equals(newKey)) {
+ return this;
+ }
+
ElementDescriptor element = map.get(oldKey);
if (element == null) {
diff --git a/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
index 1e38e7f5e6..6d47deadeb 100755
--- a/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
+++ b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
@@ -320,4 +320,19 @@ public class ErrorGroups {
/** Failed to create a directory. */
public static final int DIRECTORY_CREATION_ERR =
STORAGE_ERR_GROUP.registerErrorCode(1);
}
+
+ /** Distribution zones error group. */
+ public static class DistributionZones {
+ /** Distribution zones group. */
+ public static final ErrorGroup DISTRIBUTION_ZONES_ERR_GROUP =
ErrorGroup.newGroup("DISTRZONES", 10);
+
+ /** Distribution zone already exists. */
+ public static final int ZONE_ALREADY_EXISTS_ERR =
DISTRIBUTION_ZONES_ERR_GROUP.registerErrorCode(1);
+
+ /** Distribution zone is not found. */
+ public static final int ZONE_NOT_FOUND_ERR =
DISTRIBUTION_ZONES_ERR_GROUP.registerErrorCode(2);
+
+ /** Distribution zone rename error. */
+ public static final int ZONE_RENAME_ERR =
DISTRIBUTION_ZONES_ERR_GROUP.registerErrorCode(3);
+ }
}
diff --git a/modules/distribution-zones/build.gradle
b/modules/distribution-zones/build.gradle
new file mode 100644
index 0000000000..c4bf2b78e3
--- /dev/null
+++ b/modules/distribution-zones/build.gradle
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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-integration-test.gradle"
+apply from: "$rootDir/buildscripts/java-test-fixtures.gradle"
+
+
+dependencies {
+ annotationProcessor project(":ignite-configuration-annotation-processor")
+ api project(':ignite-configuration-api')
+ implementation project(':ignite-core')
+ implementation project(':ignite-configuration')
+ implementation project(':ignite-api')
+
+ implementation libs.jetbrains.annotations
+ implementation libs.fastutil.core
+
+ testImplementation libs.mockito.core
+ testImplementation libs.mockito.junit
+
+ testImplementation(testFixtures(project(':ignite-core')))
+ testImplementation(testFixtures(project(':ignite-configuration')))
+}
+
+description = 'ignite-distribution-zones'
diff --git a/modules/distribution-zones/pom.xml
b/modules/distribution-zones/pom.xml
new file mode 100644
index 0000000000..ed8174685d
--- /dev/null
+++ b/modules/distribution-zones/pom.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-parent</artifactId>
+ <version>1</version>
+ <relativePath>../../parent/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>ignite-distribution-zones</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-configuration-api</artifactId>
+ </dependency>
+
+ <!-- 3rd party dependencies -->
+ <dependency>
+ <groupId>org.jetbrains</groupId>
+ <artifactId>annotations</artifactId>
+ </dependency>
+
+ <!-- Test dependencies -->
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-junit-jupiter</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-configuration</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-core</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-testJar</id>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+
<artifactId>ignite-configuration-annotation-processor</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <annotationProcessorPaths>
+ <path>
+ <groupId>org.apache.ignite</groupId>
+
<artifactId>ignite-configuration-annotation-processor</artifactId>
+ <version>${project.version}</version>
+ </path>
+ </annotationProcessorPaths>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git
a/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZoneConfigurationParameters.java
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZoneConfigurationParameters.java
new file mode 100644
index 0000000000..a1332e20d3
--- /dev/null
+++
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZoneConfigurationParameters.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.distributionzones;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Distribution zone configuration.
+ */
+public class DistributionZoneConfigurationParameters {
+ /** Zone name. */
+ private final String name;
+
+ /** Data nodes auto adjust timeout. */
+ private final Integer dataNodesAutoAdjust;
+
+ /** Data nodes auto adjust scale up timeout. */
+ private final Integer dataNodesAutoAdjustScaleUp;
+
+ /** Data nodes auto adjust scale down timeout. */
+ private final Integer dataNodesAutoAdjustScaleDown;
+
+ /**
+ * The constructor.
+ */
+ private DistributionZoneConfigurationParameters(
+ String name,
+ Integer dataNodesAutoAdjust,
+ Integer dataNodesAutoAdjustScaleUp,
+ Integer dataNodesAutoAdjustScaleDown
+ ) {
+ this.name = name;
+ this.dataNodesAutoAdjust = dataNodesAutoAdjust;
+ this.dataNodesAutoAdjustScaleUp = dataNodesAutoAdjustScaleUp;
+ this.dataNodesAutoAdjustScaleDown = dataNodesAutoAdjustScaleDown;
+ }
+
+ /**
+ * Gets the zone name.
+ *
+ * @return The zone name.
+ */
+ public String name() {
+ return name;
+ }
+
+ /**
+ * Gets timeout in seconds between node added or node left topology event
itself and data nodes switch.
+ *
+ * @return Data nodes auto adjust timeout.
+ */
+ @Nullable public Integer dataNodesAutoAdjust() {
+ return dataNodesAutoAdjust;
+ }
+
+ /**
+ * Gets timeout in seconds between node added topology event itself and
data nodes switch.
+ *
+ * @return Data nodes auto adjust scale up timeout.
+ */
+ @Nullable public Integer dataNodesAutoAdjustScaleUp() {
+ return dataNodesAutoAdjustScaleUp;
+ }
+
+ /**
+ * Gets timeout in seconds between node left topology event itself and
data nodes switch.
+ *
+ * @return Data nodes auto adjust scale down timeout.
+ */
+ @Nullable public Integer dataNodesAutoAdjustScaleDown() {
+ return dataNodesAutoAdjustScaleDown;
+ }
+
+ /**
+ * Builder for distribution zone configuration.
+ */
+ public static class Builder {
+ /** Zone name. */
+ private String name;
+
+ /** Data nodes auto adjust timeout. */
+ private Integer dataNodesAutoAdjust;
+
+ /** Data nodes auto adjust scale up timeout. */
+ private Integer dataNodesAutoAdjustScaleUp;
+
+ /** Data nodes auto adjust scale down timeout. */
+ private Integer dataNodesAutoAdjustScaleDown;
+
+ /**
+ * Constructor.
+ *
+ * @param name Name.
+ */
+ public Builder(String name) {
+ if (name == null || name.isEmpty()) {
+ throw new IllegalArgumentException("Illegal distribution zone
name [name=" + name + ']');
+ }
+
+ this.name = name;
+ }
+
+ /**
+ * Sets timeout in seconds between node added or node left topology
event itself and data nodes switch.
+ *
+ * @param dataNodesAutoAdjust Timeout.
+ * @return This instance.
+ */
+ public Builder dataNodesAutoAdjust(int dataNodesAutoAdjust) {
+ this.dataNodesAutoAdjust = dataNodesAutoAdjust;
+
+ return this;
+ }
+
+ /**
+ * Sets timeout in seconds between node added topology event itself
and data nodes switch.
+ *
+ * @param dataNodesAutoAdjustScaleUp Timeout.
+ * @return This instance.
+ */
+ public Builder dataNodesAutoAdjustScaleUp(int
dataNodesAutoAdjustScaleUp) {
+ this.dataNodesAutoAdjustScaleUp = dataNodesAutoAdjustScaleUp;
+
+ return this;
+ }
+
+ /**
+ * Sets timeout in seconds between node left topology event itself and
data nodes switch.
+ *
+ * @param dataNodesAutoAdjustScaleDown Timeout in seconds between node
left topology event itself
+ * and data nodes switch.
+ * @return This instance.
+ */
+ public Builder dataNodesAutoAdjustScaleDown(int
dataNodesAutoAdjustScaleDown) {
+ this.dataNodesAutoAdjustScaleDown = dataNodesAutoAdjustScaleDown;
+
+ return this;
+ }
+
+ /**
+ * Builds the distribution zone configuration.
+ *
+ * @return Distribution zone configuration.
+ */
+ public DistributionZoneConfigurationParameters build() {
+ if (dataNodesAutoAdjust != null
+ && (dataNodesAutoAdjustScaleUp != null ||
dataNodesAutoAdjustScaleDown != null)
+ ) {
+ throw new IllegalArgumentException(
+ "Not compatible parameters [dataNodesAutoAdjust=" +
dataNodesAutoAdjust
+ + ", dataNodesAutoAdjustScaleUp=" +
dataNodesAutoAdjustScaleUp
+ + ", dataNodesAutoAdjustScaleDown=" +
dataNodesAutoAdjustScaleDown + ']'
+ );
+ }
+
+ return new DistributionZoneConfigurationParameters(
+ name,
+ dataNodesAutoAdjust,
+ dataNodesAutoAdjustScaleUp,
+ dataNodesAutoAdjustScaleDown
+ );
+ }
+ }
+}
diff --git
a/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZoneManager.java
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZoneManager.java
new file mode 100644
index 0000000000..e16493756e
--- /dev/null
+++
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZoneManager.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.distributionzones;
+
+import static org.apache.ignite.lang.ErrorGroups.Common.UNEXPECTED_ERR;
+
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import org.apache.ignite.configuration.NamedListChange;
+import
org.apache.ignite.internal.distributionzones.configuration.DistributionZoneChange;
+import
org.apache.ignite.internal.distributionzones.configuration.DistributionZoneView;
+import
org.apache.ignite.internal.distributionzones.configuration.DistributionZonesConfiguration;
+import
org.apache.ignite.internal.distributionzones.exception.DistributionZoneAlreadyExistsException;
+import
org.apache.ignite.internal.distributionzones.exception.DistributionZoneNotFoundException;
+import
org.apache.ignite.internal.distributionzones.exception.DistributionZoneRenameException;
+import org.apache.ignite.internal.manager.IgniteComponent;
+import org.apache.ignite.internal.util.IgniteSpinBusyLock;
+import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.lang.IgniteInternalException;
+import org.apache.ignite.lang.NodeStoppingException;
+
+/**
+ * Distribution zones manager.
+ */
+public class DistributionZoneManager implements IgniteComponent {
+ /** Distribution zone configuration. */
+ private final DistributionZonesConfiguration zonesConfiguration;
+
+ /** Busy lock to stop synchronously. */
+ private final IgniteSpinBusyLock busyLock = new IgniteSpinBusyLock();
+
+ /**
+ * Creates a new distribution zone manager.
+ *
+ * @param zonesConfiguration Distribution zones configuration.
+ */
+ public DistributionZoneManager(DistributionZonesConfiguration
zonesConfiguration) {
+ this.zonesConfiguration = zonesConfiguration;
+ }
+
+ /**
+ * Creates a new distribution zone with the given {@code name}
asynchronously.
+ *
+ * @param distributionZoneCfg Distribution zone configuration.
+ * @return Future representing pending completion of the operation.
+ */
+ public CompletableFuture<Void>
createZone(DistributionZoneConfigurationParameters distributionZoneCfg) {
+ Objects.requireNonNull(distributionZoneCfg, "Distribution zone
configuration is null.");
+
+ if (!busyLock.enterBusy()) {
+ throw new IgniteException(new NodeStoppingException());
+ }
+
+ try {
+ return zonesConfiguration.change(zonesChange ->
zonesChange.changeDistributionZones(zonesListChange -> {
+ try {
+ zonesListChange.create(distributionZoneCfg.name(),
zoneChange -> {
+ if (distributionZoneCfg.dataNodesAutoAdjust() == null)
{
+
zoneChange.changeDataNodesAutoAdjust(Integer.MAX_VALUE);
+ } else {
+
zoneChange.changeDataNodesAutoAdjust(distributionZoneCfg.dataNodesAutoAdjust());
+ }
+
+ if (distributionZoneCfg.dataNodesAutoAdjustScaleUp()
== null) {
+
zoneChange.changeDataNodesAutoAdjustScaleUp(Integer.MAX_VALUE);
+ } else {
+ zoneChange.changeDataNodesAutoAdjustScaleUp(
+
distributionZoneCfg.dataNodesAutoAdjustScaleUp());
+ }
+
+ if (distributionZoneCfg.dataNodesAutoAdjustScaleDown()
== null) {
+
zoneChange.changeDataNodesAutoAdjustScaleDown(Integer.MAX_VALUE);
+ } else {
+
zoneChange.changeDataNodesAutoAdjustScaleDown(distributionZoneCfg.dataNodesAutoAdjustScaleDown());
+ }
+
+ int intZoneId = zonesChange.globalIdCounter() + 1;
+ zonesChange.changeGlobalIdCounter(intZoneId);
+
+ zoneChange.changeZoneId(intZoneId);
+ });
+ } catch (IllegalArgumentException e) {
+ throw new
DistributionZoneAlreadyExistsException(distributionZoneCfg.name(), e);
+ } catch (Exception e) {
+ throw new IgniteInternalException(UNEXPECTED_ERR,
distributionZoneCfg.name(), e);
+ }
+ }));
+ } finally {
+ busyLock.leaveBusy();
+ }
+ }
+
+ /**
+ * Alters a distribution zone.
+ *
+ * @param name Distribution zone name.
+ * @param distributionZoneCfg Distribution zone configuration.
+ * @return Future representing pending completion of the operation.
+ */
+ public CompletableFuture<Void> alterZone(String name,
DistributionZoneConfigurationParameters distributionZoneCfg) {
+ Objects.requireNonNull(name, "Distribution zone name is null.");
+ Objects.requireNonNull(distributionZoneCfg, "Distribution zone
configuration is null.");
+
+ if (!busyLock.enterBusy()) {
+ throw new IgniteException(new NodeStoppingException());
+ }
+
+ try {
+ return zonesConfiguration.change(zonesChange ->
zonesChange.changeDistributionZones(zonesListChange -> {
+ NamedListChange<DistributionZoneView, DistributionZoneChange>
renameChange;
+
+ try {
+ renameChange = zonesListChange
+ .rename(name, distributionZoneCfg.name());
+ } catch (IllegalArgumentException e) {
+ throw new DistributionZoneRenameException(name,
distributionZoneCfg.name(), e);
+ } catch (Exception e) {
+ throw new IgniteInternalException(UNEXPECTED_ERR,
distributionZoneCfg.name(), e);
+ }
+
+ try {
+ renameChange
+ .update(
+ distributionZoneCfg.name(), zoneChange -> {
+ if
(distributionZoneCfg.dataNodesAutoAdjust() != null) {
+
zoneChange.changeDataNodesAutoAdjust(distributionZoneCfg.dataNodesAutoAdjust());
+
zoneChange.changeDataNodesAutoAdjustScaleUp(Integer.MAX_VALUE);
+
zoneChange.changeDataNodesAutoAdjustScaleDown(Integer.MAX_VALUE);
+ }
+
+ if
(distributionZoneCfg.dataNodesAutoAdjustScaleUp() != null) {
+
zoneChange.changeDataNodesAutoAdjustScaleUp(
+
distributionZoneCfg.dataNodesAutoAdjustScaleUp());
+
zoneChange.changeDataNodesAutoAdjust(Integer.MAX_VALUE);
+ }
+
+ if
(distributionZoneCfg.dataNodesAutoAdjustScaleDown() != null) {
+
zoneChange.changeDataNodesAutoAdjustScaleDown(
+
distributionZoneCfg.dataNodesAutoAdjustScaleDown());
+
zoneChange.changeDataNodesAutoAdjust(Integer.MAX_VALUE);
+ }
+ });
+ } catch (IllegalArgumentException e) {
+ throw new
DistributionZoneNotFoundException(distributionZoneCfg.name(), e);
+ } catch (Exception e) {
+ throw new IgniteInternalException(UNEXPECTED_ERR,
distributionZoneCfg.name(), e);
+ }
+ }));
+ } finally {
+ busyLock.leaveBusy();
+ }
+ }
+
+ /**
+ * Drops a distribution zone with the name specified.
+ *
+ * @param name Distribution zone name.
+ * @return Future representing pending completion of the operation.
+ */
+ public CompletableFuture<Void> dropZone(String name) {
+ Objects.requireNonNull(name, "Distribution zone name is null.");
+
+ if (!busyLock.enterBusy()) {
+ throw new IgniteException(new NodeStoppingException());
+ }
+
+ try {
+ return zonesConfiguration.change(zonesChange ->
zonesChange.changeDistributionZones(zonesListChange -> {
+ DistributionZoneView view = zonesListChange.get(name);
+
+ if (view == null) {
+ throw new DistributionZoneNotFoundException(name);
+ }
+
+ zonesListChange.delete(name);
+ }));
+ } finally {
+ busyLock.leaveBusy();
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void start() {
+
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void stop() throws Exception {
+
+ }
+}
diff --git
a/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/configuration/DistributionZoneConfigurationSchema.java
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/configuration/DistributionZoneConfigurationSchema.java
new file mode 100644
index 0000000000..c5dfaa6257
--- /dev/null
+++
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/configuration/DistributionZoneConfigurationSchema.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.distributionzones.configuration;
+
+import org.apache.ignite.configuration.annotation.Config;
+import org.apache.ignite.configuration.annotation.InjectedName;
+import org.apache.ignite.configuration.annotation.Value;
+import org.apache.ignite.configuration.validation.Immutable;
+import org.apache.ignite.configuration.validation.Range;
+
+/**
+ * Distribution zone configuration schema class.
+ */
+@Config
+public class DistributionZoneConfigurationSchema {
+ /** Zone name. */
+ @InjectedName
+ public String name;
+
+ /** Integer zone id. */
+ @Immutable
+ @Range(min = 1)
+ @Value(hasDefault = true)
+ public int zoneId = 1;
+
+ /** Timeout in seconds between node added or node left topology event
itself and data nodes switch. */
+ @Range(min = 0)
+ @Value(hasDefault = true)
+ public int dataNodesAutoAdjust = Integer.MAX_VALUE;
+
+ /** Timeout in seconds between node added topology event itself and data
nodes switch. */
+ @Range(min = 0)
+ @Value(hasDefault = true)
+ public int dataNodesAutoAdjustScaleUp = Integer.MAX_VALUE;
+
+ /** Timeout in seconds between node left topology event itself and data
nodes switch. */
+ @Range(min = 0)
+ @Value(hasDefault = true)
+ public int dataNodesAutoAdjustScaleDown = Integer.MAX_VALUE;
+}
diff --git
a/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/configuration/DistributionZonesConfigurationSchema.java
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/configuration/DistributionZonesConfigurationSchema.java
new file mode 100644
index 0000000000..d1be021425
--- /dev/null
+++
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/configuration/DistributionZonesConfigurationSchema.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.distributionzones.configuration;
+
+import org.apache.ignite.configuration.annotation.ConfigurationRoot;
+import org.apache.ignite.configuration.annotation.ConfigurationType;
+import org.apache.ignite.configuration.annotation.NamedConfigValue;
+import org.apache.ignite.configuration.annotation.Value;
+
+/**
+ * Distribution zones configuration schema.
+ */
+@ConfigurationRoot(rootName = "zone", type = ConfigurationType.DISTRIBUTED)
+public class DistributionZonesConfigurationSchema {
+ /** Global integer id counter. Used as an auto-increment counter to
generate integer identifiers for distribution zone. */
+ @Value(hasDefault = true)
+ public int globalIdCounter = 0;
+
+ /** List of configured distribution zones. */
+ @NamedConfigValue
+ public DistributionZoneConfigurationSchema distributionZones;
+}
diff --git
a/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/exception/DistributionZoneAlreadyExistsException.java
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/exception/DistributionZoneAlreadyExistsException.java
new file mode 100644
index 0000000000..13e2ff5ea5
--- /dev/null
+++
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/exception/DistributionZoneAlreadyExistsException.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.distributionzones.exception;
+
+import static
org.apache.ignite.lang.ErrorGroups.DistributionZones.ZONE_ALREADY_EXISTS_ERR;
+
+import java.util.UUID;
+import org.apache.ignite.lang.IgniteInternalException;
+
+/**
+ * This exception is thrown when a new distribution zone failed to be created,
+ * because a distribution zone with same name already exists.
+ */
+public class DistributionZoneAlreadyExistsException extends
IgniteInternalException {
+ /**
+ * The constructor.
+ *
+ * @param zoneName Zone name.
+ * @param cause Optional nested exception (can be {@code null}).
+ */
+ public DistributionZoneAlreadyExistsException(String zoneName, Throwable
cause) {
+ super(ZONE_ALREADY_EXISTS_ERR, "Distribution zone already exists
[zoneName=" + zoneName + ']', cause);
+ }
+
+ /**
+ * The constructor is used for creating an exception instance that is
thrown from a remote server.
+ *
+ * @param traceId Trace id.
+ * @param code Error code.
+ * @param message Error message.
+ * @param cause Cause exception.
+ */
+ public DistributionZoneAlreadyExistsException(UUID traceId, int code,
String message, Throwable cause) {
+ super(traceId, code, message, cause);
+ }
+}
diff --git
a/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/exception/DistributionZoneNotFoundException.java
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/exception/DistributionZoneNotFoundException.java
new file mode 100644
index 0000000000..a12853fbe9
--- /dev/null
+++
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/exception/DistributionZoneNotFoundException.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.distributionzones.exception;
+
+import static
org.apache.ignite.lang.ErrorGroups.DistributionZones.ZONE_NOT_FOUND_ERR;
+
+import java.util.UUID;
+import org.apache.ignite.lang.IgniteInternalException;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Exception is thrown when appropriate distribution zone can`t be found.
+ */
+public class DistributionZoneNotFoundException extends IgniteInternalException
{
+ /**
+ * The constructor.
+ *
+ * @param zoneName Zone name.
+ */
+ public DistributionZoneNotFoundException(String zoneName) {
+ this("Distribution zone is not found [zoneName=" + zoneName + ']',
null);
+ }
+
+ /**
+ * The constructor.
+ *
+ * @param zoneName Zone name.
+ * @param cause Optional nested exception (can be {@code null}).
+ */
+ public DistributionZoneNotFoundException(String zoneName, @Nullable
Throwable cause) {
+ super(ZONE_NOT_FOUND_ERR, "Distribution zone is not found [zoneName="
+ zoneName + ']', cause);
+ }
+
+ /**
+ * The constructor is used for creating an exception instance that is
thrown from a remote server.
+ *
+ * @param traceId Trace id.
+ * @param code Error code.
+ * @param message Error message.
+ * @param cause Cause exception.
+ */
+ public DistributionZoneNotFoundException(UUID traceId, int code, String
message, Throwable cause) {
+ super(traceId, code, message, cause);
+ }
+}
diff --git
a/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/exception/DistributionZoneRenameException.java
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/exception/DistributionZoneRenameException.java
new file mode 100644
index 0000000000..ff51eae889
--- /dev/null
+++
b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/exception/DistributionZoneRenameException.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.distributionzones.exception;
+
+import static
org.apache.ignite.lang.ErrorGroups.DistributionZones.ZONE_RENAME_ERR;
+
+import java.util.UUID;
+import org.apache.ignite.lang.IgniteInternalException;
+
+/**
+ * This exception is thrown when a distribution zone with old name doesn't
exist or a distribution zone with new name already exists.
+ */
+public class DistributionZoneRenameException extends IgniteInternalException {
+ /**
+ * The constructor.
+ *
+ * @param oldName Old name.
+ * @param newName New name.
+ */
+ public DistributionZoneRenameException(String oldName, String newName,
Throwable cause) {
+ super(ZONE_RENAME_ERR, "Distribution zone with old name doesn't exist
or "
+ + "distribution zone with new name already exists [oldName=" +
oldName + "newName=" + newName + ']', cause);
+ }
+
+ /**
+ * The constructor is used for creating an exception instance that is
thrown from a remote server.
+ *
+ * @param traceId Trace id.
+ * @param code Error code.
+ * @param message Error message.
+ * @param cause Cause exception.
+ */
+ public DistributionZoneRenameException(UUID traceId, int code, String
message, Throwable cause) {
+ super(traceId, code, message, cause);
+ }
+}
diff --git
a/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneConfigurationParametersTest.java
b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneConfigurationParametersTest.java
new file mode 100644
index 0000000000..09889cd752
--- /dev/null
+++
b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneConfigurationParametersTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.distributionzones;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for {@link DistributionZoneConfigurationParameters}.
+ */
+class DistributionZoneConfigurationParametersTest {
+ private static final String ZONE_NAME = "zone1";
+
+ @Test
+ public void testDefaultValues() {
+ DistributionZoneConfigurationParameters zoneCfg = new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME).build();
+
+ assertEquals(ZONE_NAME, zoneCfg.name());
+ assertEquals(null, zoneCfg.dataNodesAutoAdjust());
+ assertEquals(null, zoneCfg.dataNodesAutoAdjustScaleUp());
+ assertEquals(null, zoneCfg.dataNodesAutoAdjustScaleDown());
+ }
+
+ @Test
+ public void testAutoAdjust() {
+ DistributionZoneConfigurationParameters zoneCfg = new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+ .dataNodesAutoAdjust(100)
+ .build();
+
+ assertEquals(ZONE_NAME, zoneCfg.name());
+ assertEquals(100, zoneCfg.dataNodesAutoAdjust());
+ assertEquals(null, zoneCfg.dataNodesAutoAdjustScaleUp());
+ assertEquals(null, zoneCfg.dataNodesAutoAdjustScaleDown());
+ }
+
+ @Test
+ public void testAutoAdjustScaleUp() {
+ DistributionZoneConfigurationParameters zoneCfg = new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+ .dataNodesAutoAdjustScaleUp(100)
+ .build();
+
+ assertEquals(ZONE_NAME, zoneCfg.name());
+ assertEquals(null, zoneCfg.dataNodesAutoAdjust());
+ assertEquals(100, zoneCfg.dataNodesAutoAdjustScaleUp());
+ assertEquals(null, zoneCfg.dataNodesAutoAdjustScaleDown());
+ }
+
+ @Test
+ public void testAutoAdjustScaleDown() {
+ DistributionZoneConfigurationParameters zoneCfg = new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+ .dataNodesAutoAdjustScaleDown(100)
+ .build();
+
+ assertEquals(ZONE_NAME, zoneCfg.name());
+ assertEquals(null, zoneCfg.dataNodesAutoAdjust());
+ assertEquals(null, zoneCfg.dataNodesAutoAdjustScaleUp());
+ assertEquals(100, zoneCfg.dataNodesAutoAdjustScaleDown());
+ }
+
+ @Test
+ public void testIncompatibleValues1() {
+ assertThrows(IllegalArgumentException.class,
+ () -> new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+ .dataNodesAutoAdjust(1)
+ .dataNodesAutoAdjustScaleUp(1)
+ .build());
+ }
+
+ @Test
+ public void testIncompatibleValues2() {
+ assertThrows(IllegalArgumentException.class,
+ () -> new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+ .dataNodesAutoAdjust(1)
+ .dataNodesAutoAdjustScaleDown(1)
+ .build());
+ }
+
+ @Test
+ public void testNullName() {
+ assertThrows(IllegalArgumentException.class,
+ () -> new
DistributionZoneConfigurationParameters.Builder(null));
+ }
+
+ @Test
+ public void testEmptyName() {
+ assertThrows(IllegalArgumentException.class,
+ () -> new DistributionZoneConfigurationParameters.Builder(""));
+ }
+}
diff --git
a/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerTest.java
b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerTest.java
new file mode 100644
index 0000000000..4681a27678
--- /dev/null
+++
b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerTest.java
@@ -0,0 +1,442 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.distributionzones;
+
+import static
org.apache.ignite.configuration.annotation.ConfigurationType.DISTRIBUTED;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import org.apache.ignite.configuration.ConfigurationChangeException;
+import org.apache.ignite.internal.configuration.ConfigurationRegistry;
+import
org.apache.ignite.internal.configuration.storage.TestConfigurationStorage;
+import
org.apache.ignite.internal.distributionzones.configuration.DistributionZoneConfiguration;
+import
org.apache.ignite.internal.distributionzones.configuration.DistributionZonesConfiguration;
+import
org.apache.ignite.internal.distributionzones.exception.DistributionZoneAlreadyExistsException;
+import
org.apache.ignite.internal.distributionzones.exception.DistributionZoneNotFoundException;
+import
org.apache.ignite.internal.distributionzones.exception.DistributionZoneRenameException;
+import org.apache.ignite.internal.testframework.IgniteAbstractTest;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for distribution zone manager.
+ */
+class DistributionZoneManagerTest extends IgniteAbstractTest {
+ private static final String ZONE_NAME = "zone1";
+
+ private static final String NEW_ZONE_NAME = "zone2";
+
+ private final ConfigurationRegistry registry = new ConfigurationRegistry(
+ List.of(DistributionZonesConfiguration.KEY),
+ Map.of(),
+ new TestConfigurationStorage(DISTRIBUTED),
+ List.of(),
+ List.of()
+ );
+
+ private DistributionZoneManager distributionZoneManager;
+
+ @BeforeEach
+ public void setUp() {
+ registry.start();
+
+ registry.initializeDefaults();
+
+ DistributionZonesConfiguration zonesConfiguration =
registry.getConfiguration(DistributionZonesConfiguration.KEY);
+ distributionZoneManager = new
DistributionZoneManager(zonesConfiguration);
+ }
+
+ @AfterEach
+ public void tearDown() throws Exception {
+ registry.stop();
+ }
+
+ @Test
+ public void testCreateZoneWithAutoAdjust() throws Exception {
+ distributionZoneManager.createZone(
+ new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME).dataNodesAutoAdjust(100).build()
+ )
+ .get(5, TimeUnit.SECONDS);
+
+ DistributionZoneConfiguration zone1 =
registry.getConfiguration(DistributionZonesConfiguration.KEY).distributionZones()
+ .get(ZONE_NAME);
+
+ assertNotNull(zone1);
+ assertEquals(ZONE_NAME, zone1.name().value());
+ assertEquals(Integer.MAX_VALUE,
zone1.dataNodesAutoAdjustScaleUp().value());
+ assertEquals(Integer.MAX_VALUE,
zone1.dataNodesAutoAdjustScaleDown().value());
+ assertEquals(100, zone1.dataNodesAutoAdjust().value());
+ }
+
+ @Test
+ public void testCreateZoneWithAutoAdjustScaleUp() throws Exception {
+ distributionZoneManager.createZone(
+ new DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+ .dataNodesAutoAdjustScaleUp(100).build()
+ )
+ .get(5, TimeUnit.SECONDS);
+
+ DistributionZoneConfiguration zone1 =
registry.getConfiguration(DistributionZonesConfiguration.KEY).distributionZones()
+ .get(ZONE_NAME);
+
+ assertNotNull(zone1);
+ assertEquals(ZONE_NAME, zone1.name().value());
+ assertEquals(100, zone1.dataNodesAutoAdjustScaleUp().value());
+ assertEquals(Integer.MAX_VALUE,
zone1.dataNodesAutoAdjustScaleDown().value());
+ assertEquals(Integer.MAX_VALUE, zone1.dataNodesAutoAdjust().value());
+
+ distributionZoneManager.dropZone(ZONE_NAME).get(5, TimeUnit.SECONDS);
+
+ zone1 =
registry.getConfiguration(DistributionZonesConfiguration.KEY).distributionZones()
+ .get(ZONE_NAME);
+
+ assertNull(zone1);
+ }
+
+ @Test
+ public void testCreateZoneWithAutoAdjustScaleDown() throws Exception {
+ distributionZoneManager.createZone(
+ new DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+ .dataNodesAutoAdjustScaleDown(200).build()
+ )
+ .get(5, TimeUnit.SECONDS);
+
+ DistributionZoneConfiguration zone1 =
registry.getConfiguration(DistributionZonesConfiguration.KEY).distributionZones()
+ .get(ZONE_NAME);
+
+ assertNotNull(zone1);
+ assertEquals(ZONE_NAME, zone1.name().value());
+ assertEquals(Integer.MAX_VALUE,
zone1.dataNodesAutoAdjustScaleUp().value());
+ assertEquals(200, zone1.dataNodesAutoAdjustScaleDown().value());
+ assertEquals(Integer.MAX_VALUE, zone1.dataNodesAutoAdjust().value());
+
+ distributionZoneManager.dropZone(ZONE_NAME).get(5, TimeUnit.SECONDS);
+
+ zone1 =
registry.getConfiguration(DistributionZonesConfiguration.KEY).distributionZones()
+ .get(ZONE_NAME);
+
+ assertNull(zone1);
+ }
+
+ @Test
+ public void testCreateZoneIfExists() throws Exception {
+ Exception e = null;
+
+ distributionZoneManager.createZone(
+ new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME).dataNodesAutoAdjust(100).build()
+ ).get(5, TimeUnit.SECONDS);
+
+ try {
+ distributionZoneManager.createZone(
+ new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME).dataNodesAutoAdjust(100).build()
+ ).get(5, TimeUnit.SECONDS);
+ } catch (Exception e0) {
+ e = e0;
+ }
+
+ assertTrue(e != null);
+ assertTrue(e.getCause().getCause() instanceof
DistributionZoneAlreadyExistsException, e.toString());
+ }
+
+ @Test
+ public void testDropZoneIfNotExists() {
+ Exception e = null;
+
+ try {
+ distributionZoneManager.dropZone(ZONE_NAME).get(5,
TimeUnit.SECONDS);
+ } catch (Exception e0) {
+ e = e0;
+ }
+
+ assertTrue(e != null);
+ assertTrue(e.getCause().getCause() instanceof
DistributionZoneNotFoundException, e.toString());
+ }
+
+ @Test
+ public void testUpdateZone() throws Exception {
+ distributionZoneManager.createZone(
+ new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME).dataNodesAutoAdjust(100).build()
+ )
+ .get(5, TimeUnit.SECONDS);
+
+ DistributionZoneConfiguration zone1 =
registry.getConfiguration(DistributionZonesConfiguration.KEY).distributionZones()
+ .get(ZONE_NAME);
+
+ assertNotNull(zone1);
+ assertEquals(ZONE_NAME, zone1.name().value());
+ assertEquals(Integer.MAX_VALUE,
zone1.dataNodesAutoAdjustScaleUp().value());
+ assertEquals(Integer.MAX_VALUE,
zone1.dataNodesAutoAdjustScaleDown().value());
+ assertEquals(100, zone1.dataNodesAutoAdjust().value());
+
+
+ distributionZoneManager.alterZone(ZONE_NAME, new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+
.dataNodesAutoAdjustScaleUp(200).dataNodesAutoAdjustScaleDown(300).build())
+ .get(5, TimeUnit.SECONDS);
+
+ zone1 =
registry.getConfiguration(DistributionZonesConfiguration.KEY).distributionZones()
+ .get(ZONE_NAME);
+
+ assertNotNull(zone1);
+ assertEquals(200, zone1.dataNodesAutoAdjustScaleUp().value());
+ assertEquals(300, zone1.dataNodesAutoAdjustScaleDown().value());
+ assertEquals(Integer.MAX_VALUE, zone1.dataNodesAutoAdjust().value());
+
+
+ distributionZoneManager.alterZone(ZONE_NAME, new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+ .dataNodesAutoAdjustScaleUp(400).build())
+ .get(5, TimeUnit.SECONDS);
+
+ zone1 =
registry.getConfiguration(DistributionZonesConfiguration.KEY).distributionZones()
+ .get(ZONE_NAME);
+
+ assertNotNull(zone1);
+ assertEquals(400, zone1.dataNodesAutoAdjustScaleUp().value());
+ assertEquals(300, zone1.dataNodesAutoAdjustScaleDown().value());
+ assertEquals(Integer.MAX_VALUE, zone1.dataNodesAutoAdjust().value());
+
+
+ distributionZoneManager.alterZone(ZONE_NAME, new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+ .dataNodesAutoAdjust(500).build())
+ .get(5, TimeUnit.SECONDS);
+
+ zone1 =
registry.getConfiguration(DistributionZonesConfiguration.KEY).distributionZones()
+ .get(ZONE_NAME);
+
+ assertNotNull(zone1);
+ assertEquals(Integer.MAX_VALUE,
zone1.dataNodesAutoAdjustScaleUp().value());
+ assertEquals(Integer.MAX_VALUE,
zone1.dataNodesAutoAdjustScaleDown().value());
+ assertEquals(500, zone1.dataNodesAutoAdjust().value());
+ }
+
+ @Test
+ public void testRenameZone() throws Exception {
+ distributionZoneManager.createZone(
+ new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME).dataNodesAutoAdjust(100).build()
+ )
+ .get(5, TimeUnit.SECONDS);
+
+ distributionZoneManager.alterZone(ZONE_NAME,
+ new
DistributionZoneConfigurationParameters.Builder(NEW_ZONE_NAME).build())
+ .get(5, TimeUnit.SECONDS);
+
+ DistributionZoneConfiguration zone1 =
registry.getConfiguration(DistributionZonesConfiguration.KEY).distributionZones()
+ .get(ZONE_NAME);
+
+ DistributionZoneConfiguration zone2 =
registry.getConfiguration(DistributionZonesConfiguration.KEY)
+ .distributionZones()
+ .get(NEW_ZONE_NAME);
+
+ assertNull(zone1);
+ assertNotNull(zone2);
+ assertEquals(NEW_ZONE_NAME, zone2.name().value());
+ assertEquals(Integer.MAX_VALUE,
zone2.dataNodesAutoAdjustScaleUp().value());
+ assertEquals(Integer.MAX_VALUE,
zone2.dataNodesAutoAdjustScaleDown().value());
+ assertEquals(100, zone2.dataNodesAutoAdjust().value());
+ }
+
+ @Test
+ public void testUpdateAndRenameZone() throws Exception {
+ distributionZoneManager.createZone(
+ new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME).dataNodesAutoAdjust(100).build()
+ )
+ .get(5, TimeUnit.SECONDS);
+
+ distributionZoneManager.alterZone(ZONE_NAME,
+ new
DistributionZoneConfigurationParameters.Builder(NEW_ZONE_NAME).dataNodesAutoAdjust(400).build())
+ .get(5, TimeUnit.SECONDS);
+
+ DistributionZoneConfiguration zone1 =
registry.getConfiguration(DistributionZonesConfiguration.KEY).distributionZones()
+ .get(ZONE_NAME);
+
+ DistributionZoneConfiguration zone2 =
registry.getConfiguration(DistributionZonesConfiguration.KEY)
+ .distributionZones()
+ .get(NEW_ZONE_NAME);
+
+ assertNull(zone1);
+ assertNotNull(zone2);
+ assertEquals(NEW_ZONE_NAME, zone2.name().value());
+ assertEquals(Integer.MAX_VALUE,
zone2.dataNodesAutoAdjustScaleUp().value());
+ assertEquals(Integer.MAX_VALUE,
zone2.dataNodesAutoAdjustScaleDown().value());
+ assertEquals(400, zone2.dataNodesAutoAdjust().value());
+ }
+
+ @Test
+ public void testAlterZoneRename1() {
+ Exception e = null;
+
+ try {
+ distributionZoneManager.alterZone(ZONE_NAME, new
DistributionZoneConfigurationParameters.Builder(NEW_ZONE_NAME)
+ .dataNodesAutoAdjust(100).build()).get(5,
TimeUnit.SECONDS);
+ } catch (Exception e0) {
+ e = e0;
+ }
+
+ assertTrue(e != null);
+ assertTrue(e.getCause().getCause() instanceof
DistributionZoneRenameException, e.toString());
+ }
+
+ @Test
+ public void testAlterZoneRename2() throws Exception {
+ Exception e = null;
+
+ distributionZoneManager.createZone(new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+ .dataNodesAutoAdjust(100).build()).get(5, TimeUnit.SECONDS);
+
+ distributionZoneManager.createZone(new
DistributionZoneConfigurationParameters.Builder(NEW_ZONE_NAME)
+ .dataNodesAutoAdjust(100).build()).get(5, TimeUnit.SECONDS);
+
+ try {
+ distributionZoneManager.alterZone(ZONE_NAME, new
DistributionZoneConfigurationParameters.Builder(NEW_ZONE_NAME)
+ .dataNodesAutoAdjust(100).build()).get(5,
TimeUnit.SECONDS);
+ } catch (Exception e0) {
+ e = e0;
+ }
+
+ assertTrue(e != null);
+ assertTrue(e.getCause().getCause() instanceof
DistributionZoneRenameException, e.toString());
+ }
+
+ @Test
+ public void testAlterZoneIfExists() {
+ Exception e = null;
+
+ try {
+ distributionZoneManager.alterZone(ZONE_NAME, new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+ .dataNodesAutoAdjust(100).build()).get(5,
TimeUnit.SECONDS);
+ } catch (Exception e0) {
+ e = e0;
+ }
+
+ assertTrue(e != null);
+ assertTrue(e.getCause().getCause() instanceof
DistributionZoneNotFoundException, e.toString());
+ }
+
+ @Test
+ public void testCreateZoneWithWrongAutoAdjust() {
+ Exception e = null;
+
+ try {
+ distributionZoneManager.createZone(new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+ .dataNodesAutoAdjust(-10).build()).get(5,
TimeUnit.SECONDS);
+ } catch (Exception e0) {
+ e = e0;
+ }
+
+ assertTrue(e != null);
+ assertTrue(e.getCause() instanceof ConfigurationChangeException,
e.toString());
+ }
+
+ @Test
+ public void testCreateZoneWithWrongSeparatedAutoAdjust1() {
+ Exception e = null;
+
+ try {
+ distributionZoneManager.createZone(new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+
.dataNodesAutoAdjustScaleUp(-100).dataNodesAutoAdjustScaleDown(1).build()).get(5,
TimeUnit.SECONDS);
+ } catch (Exception e0) {
+ e = e0;
+ }
+
+ assertTrue(e != null);
+ assertTrue(e.getCause() instanceof ConfigurationChangeException,
e.toString());
+ }
+
+ @Test
+ public void testCreateZoneWithWrongSeparatedAutoAdjust2() {
+ Exception e = null;
+
+ try {
+ distributionZoneManager.createZone(new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME)
+
.dataNodesAutoAdjustScaleUp(1).dataNodesAutoAdjustScaleDown(-100).build()).get(5,
TimeUnit.SECONDS);
+ } catch (Exception e0) {
+ e = e0;
+ }
+
+ assertTrue(e != null);
+ assertTrue(e.getCause() instanceof ConfigurationChangeException,
e.toString());
+ }
+
+ @Test
+ public void testCreateZoneWithNullConfiguration() {
+ Exception e = null;
+
+ try {
+ distributionZoneManager.createZone(null).get(5, TimeUnit.SECONDS);
+ } catch (Exception e0) {
+ e = e0;
+ }
+
+ assertTrue(e != null);
+ assertTrue(e instanceof NullPointerException, e.toString());
+ assertEquals("Distribution zone configuration is null.",
e.getMessage(), e.toString());
+ }
+
+ @Test
+ public void testAlterZoneWithNullName() {
+ Exception e = null;
+
+ try {
+ distributionZoneManager.alterZone(null, new
DistributionZoneConfigurationParameters.Builder(ZONE_NAME).build())
+ .get(5, TimeUnit.SECONDS);
+ } catch (Exception e0) {
+ e = e0;
+ }
+
+ assertTrue(e != null);
+ assertTrue(e instanceof NullPointerException, e.toString());
+ assertEquals("Distribution zone name is null.", e.getMessage(),
e.toString());
+ }
+
+ @Test
+ public void testAlterZoneWithNullConfiguration() {
+ Exception e = null;
+
+ try {
+ distributionZoneManager.alterZone(ZONE_NAME, null)
+ .get(5, TimeUnit.SECONDS);
+ } catch (Exception e0) {
+ e = e0;
+ }
+
+ assertTrue(e != null);
+ assertTrue(e instanceof NullPointerException, e.toString());
+ assertEquals("Distribution zone configuration is null.",
e.getMessage(), e.toString());
+ }
+
+ @Test
+ public void testDropZoneWithNullName() {
+ Exception e = null;
+
+ try {
+ distributionZoneManager.dropZone(null)
+ .get(5, TimeUnit.SECONDS);
+ } catch (Exception e0) {
+ e = e0;
+ }
+
+ assertTrue(e != null);
+ assertTrue(e instanceof NullPointerException, e.toString());
+ assertEquals("Distribution zone name is null.", e.getMessage(),
e.toString());
+ }
+}
diff --git
a/modules/platforms/dotnet/Apache.Ignite.Internal.Generators/ErrorGroupsGenerator.cs
b/modules/platforms/dotnet/Apache.Ignite.Internal.Generators/ErrorGroupsGenerator.cs
index 169c8bc5d2..9ed77fe7af 100644
---
a/modules/platforms/dotnet/Apache.Ignite.Internal.Generators/ErrorGroupsGenerator.cs
+++
b/modules/platforms/dotnet/Apache.Ignite.Internal.Generators/ErrorGroupsGenerator.cs
@@ -58,7 +58,7 @@ namespace Apache.Ignite.Internal.Generators
// ErrorGroup TX_ERR_GROUP = ErrorGroup.newGroup("TX", 7);
var javaErrorGroups = Regex.Matches(
javaErrorGroupsText,
- @"public static class ([A-Za-z]+) {\s+/\*\*.*?\*/\s+public
static final ErrorGroup ([\w_]+)_ERR_GROUP = ErrorGroup.newGroup\(""([A-Z]+)"",
(\d+)",
+ @"public static class ([A-Za-z]+) {\s+/\*\*.*?\*/\s+public
static final ErrorGroup ([\w_]+)_ERR_GROUP = ErrorGroup.newGroup\(""([\w_]+)"",
(\d+)",
RegexOptions.Singleline | RegexOptions.CultureInvariant)
.Cast<Match>()
.Select(x => (ClassName: x.Groups[1].Value, GroupName:
x.Groups[2].Value, ShortGroupName: x.Groups[3].Value, Code:
int.Parse(x.Groups[4].Value, CultureInfo.InvariantCulture)))
diff --git a/modules/platforms/dotnet/Apache.Ignite.Tests/ErrorGroupTests.cs
b/modules/platforms/dotnet/Apache.Ignite.Tests/ErrorGroupTests.cs
index 1b1fd9a9b5..fb62ee9c0f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/ErrorGroupTests.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/ErrorGroupTests.cs
@@ -173,6 +173,10 @@ namespace Apache.Ignite.Tests
Assert.AreEqual(8, ErrorGroups.Replicator.GroupCode);
Assert.AreEqual("REP", ErrorGroups.Replicator.GroupName);
Assert.AreEqual("REP", ErrorGroups.GetGroupName(8));
+
+ Assert.AreEqual(10, ErrorGroups.DistributionZones.GroupCode);
+ Assert.AreEqual("DISTRZONES",
ErrorGroups.DistributionZones.GroupName);
+ Assert.AreEqual("DISTRZONES", ErrorGroups.GetGroupName(10));
}
[Test]
diff --git a/modules/runner/build.gradle b/modules/runner/build.gradle
index c88d6665f5..f4a7cffc9f 100644
--- a/modules/runner/build.gradle
+++ b/modules/runner/build.gradle
@@ -51,6 +51,7 @@ dependencies {
implementation project(':ignite-cluster-management')
implementation project(':ignite-metrics')
implementation project(':ignite-replicator')
+ implementation project(':ignite-distribution-zones')
implementation libs.jetbrains.annotations
implementation libs.micronaut.inject
implementation libs.micronaut.validation
diff --git a/modules/runner/pom.xml b/modules/runner/pom.xml
index 9628a668b8..ac460eefd3 100644
--- a/modules/runner/pom.xml
+++ b/modules/runner/pom.xml
@@ -123,6 +123,11 @@
<artifactId>ignite-metrics</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-distribution-zones</artifactId>
+ </dependency>
+
<!-- 3rd party dependencies -->
<dependency>
<groupId>org.slf4j</groupId>
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 bee5d6a461..4afdfb0f44 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
@@ -57,6 +57,8 @@ import
org.apache.ignite.internal.configuration.ServiceLoaderModulesProvider;
import org.apache.ignite.internal.configuration.storage.ConfigurationStorage;
import
org.apache.ignite.internal.configuration.storage.DistributedConfigurationStorage;
import
org.apache.ignite.internal.configuration.storage.LocalConfigurationStorage;
+import org.apache.ignite.internal.distributionzones.DistributionZoneManager;
+import
org.apache.ignite.internal.distributionzones.configuration.DistributionZonesConfiguration;
import org.apache.ignite.internal.hlc.HybridClock;
import org.apache.ignite.internal.hlc.HybridClockImpl;
import org.apache.ignite.internal.index.IndexManager;
@@ -230,6 +232,8 @@ public class IgniteImpl implements Ignite {
/** Metric manager. */
private final MetricManager metricManager;
+ private final DistributionZoneManager distributionZoneManager;
+
/** Creator for volatile {@link
org.apache.ignite.internal.raft.storage.LogStorageFactory} instances. */
private final VolatileLogStorageFactoryCreator
volatileLogStorageFactoryCreator;
@@ -436,6 +440,11 @@ public class IgniteImpl implements Ignite {
sql,
() -> cmgMgr.clusterState().thenApply(s ->
s.clusterTag().clusterId())
);
+
+ DistributionZonesConfiguration zonesConfiguration =
clusterCfgMgr.configurationRegistry()
+ .getConfiguration(DistributionZonesConfiguration.KEY);
+
+ distributionZoneManager = new
DistributionZoneManager(zonesConfiguration);
}
private RestComponent createRestComponent(String name) {
@@ -544,6 +553,7 @@ public class IgniteImpl implements Ignite {
metaStorageMgr,
clusterCfgMgr,
metricManager,
+ distributionZoneManager,
computeComponent,
replicaMgr,
txManager,
@@ -794,4 +804,9 @@ public class IgniteImpl implements Ignite {
public ClusterNode node() {
return clusterSvc.topologyService().localMember();
}
+
+ @TestOnly
+ public DistributionZoneManager distributionZoneManager() {
+ return distributionZoneManager;
+ }
}
diff --git a/parent/pom.xml b/parent/pom.xml
index e698c6fabb..ab3c4bca9f 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -297,6 +297,12 @@
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-distribution-zones</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-cluster-management</artifactId>
diff --git a/pom.xml b/pom.xml
index ce543b9a99..a91a0c2fcd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,6 +54,7 @@
<module>modules/configuration-annotation-processor</module>
<module>modules/configuration-api</module>
<module>modules/core</module>
+ <module>modules/distribution-zones</module>
<module>modules/file-io</module>
<module>modules/index</module>
<module>modules/jacoco-report</module>
diff --git a/settings.gradle b/settings.gradle
index 5d722e1a26..ff78663c9d 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -64,6 +64,7 @@ include(':packaging-cli')
include(':packaging-db')
include(':packaging')
include(':ignite-replicator')
+include(':ignite-distribution-zones')
project(":ignite-examples").projectDir = file('examples')
project(":ignite-page-memory").projectDir = file('modules/page-memory')
@@ -113,6 +114,7 @@ project(":ignite-replicator").projectDir =
file('modules/replicator')
project(":packaging-cli").projectDir = file('packaging/cli')
project(":packaging-db").projectDir = file('packaging/db')
project(":packaging").projectDir = file('packaging')
+project(":ignite-distribution-zones").projectDir =
file('modules/distribution-zones')
ext.isCiServer = System.getenv().containsKey("IGNITE_CI")