This is an automated email from the ASF dual-hosted git repository.
ritesh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 5d87d0eb75 HDDS-6901. Configure HDDS volume reserved as percentage of
the volume space. (#3532)
5d87d0eb75 is described below
commit 5d87d0eb75c3e8b42993f7687244f8ec488878ee
Author: Aswin Shakil Balasubramanian <[email protected]>
AuthorDate: Mon Jul 11 11:33:59 2022 -0700
HDDS-6901. Configure HDDS volume reserved as percentage of the volume
space. (#3532)
* HDDS-6901. Configure HDDS volume reserved as a percentage of the volume
space.
Co-authored-by: Aswin Shakil Balasubramanian <[email protected]>
---
.../org/apache/hadoop/hdds/scm/ScmConfigKeys.java | 3 +
.../common/src/main/resources/ozone-default.xml | 8 ++
.../hadoop/hdds/conf/ConfigurationSource.java | 8 ++
.../ozone/container/common/volume/VolumeInfo.java | 33 ++++-
.../ozone/container/common/volume/VolumeUsage.java | 9 +-
.../common/volume/TestReservedVolumeSpace.java | 149 +++++++++++++++++++++
6 files changed, 204 insertions(+), 6 deletions(-)
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/ScmConfigKeys.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/ScmConfigKeys.java
index 3259b5b137..49789f4d70 100644
---
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/ScmConfigKeys.java
+++
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/ScmConfigKeys.java
@@ -214,6 +214,9 @@ public final class ScmConfigKeys {
public static final String HDDS_DATANODE_DIR_KEY = "hdds.datanode.dir";
public static final String HDDS_DATANODE_DIR_DU_RESERVED =
"hdds.datanode.dir.du.reserved";
+ public static final String HDDS_DATANODE_DIR_DU_RESERVED_PERCENT =
+ "hdds.datanode.dir.du.reserved.percent";
+ public static final float HDDS_DATANODE_DIR_DU_RESERVED_PERCENT_DEFAULT = 0;
public static final String HDDS_REST_CSRF_ENABLED_KEY =
"hdds.rest.rest-csrf.enabled";
public static final boolean HDDS_REST_CSRF_ENABLED_DEFAULT = false;
diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml
b/hadoop-hdds/common/src/main/resources/ozone-default.xml
index d1ee50af21..9fa3dd3ab8 100644
--- a/hadoop-hdds/common/src/main/resources/ozone-default.xml
+++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml
@@ -166,6 +166,14 @@
Such as /dir1:100B, /dir2:200MB, means dir1 reserves 100 bytes and dir2
reserves 200 MB.
</description>
</property>
+ <property>
+ <name>hdds.datanode.dir.du.reserved.percent</name>
+ <value/>
+ <tag>OZONE, CONTAINER, STORAGE, MANAGEMENT</tag>
+ <description>Percentage of volume that should be reserved. This space is
left free for other usage.
+ The value should be between 0-1. Such as 0.1 which means 10% of volume
space will be reserved.
+ </description>
+ </property>
<property>
<name>hdds.datanode.volume.choosing.policy</name>
<value/>
diff --git
a/hadoop-hdds/config/src/main/java/org/apache/hadoop/hdds/conf/ConfigurationSource.java
b/hadoop-hdds/config/src/main/java/org/apache/hadoop/hdds/conf/ConfigurationSource.java
index 22c74ff325..8c4ee7cd2f 100644
---
a/hadoop-hdds/config/src/main/java/org/apache/hadoop/hdds/conf/ConfigurationSource.java
+++
b/hadoop-hdds/config/src/main/java/org/apache/hadoop/hdds/conf/ConfigurationSource.java
@@ -143,6 +143,14 @@ public interface ConfigurationSource {
return configMap;
}
+ /**
+ * Checks if the property <value> is set.
+ * @param key The property name.
+ * @return true if the value is set else false.
+ */
+ default boolean isConfigured(String key) {
+ return get(key) != null;
+ }
/**
* Create a Configuration object and inject the required configuration
values.
*
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/VolumeInfo.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/VolumeInfo.java
index 71063e23fc..6773b6ff64 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/VolumeInfo.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/VolumeInfo.java
@@ -33,6 +33,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static
org.apache.hadoop.hdds.scm.ScmConfigKeys.HDDS_DATANODE_DIR_DU_RESERVED;
+import static
org.apache.hadoop.hdds.scm.ScmConfigKeys.HDDS_DATANODE_DIR_DU_RESERVED_PERCENT;
+import static
org.apache.hadoop.hdds.scm.ScmConfigKeys.HDDS_DATANODE_DIR_DU_RESERVED_PERCENT_DEFAULT;
/**
* Stores information about a disk/volume.
@@ -134,6 +136,16 @@ public final class VolumeInfo {
}
private long getReserved(ConfigurationSource conf) {
+ if (conf.isConfigured(HDDS_DATANODE_DIR_DU_RESERVED_PERCENT)
+ && conf.isConfigured(HDDS_DATANODE_DIR_DU_RESERVED)) {
+ LOG.error("Both {} and {} are set. Set either one, not both. If the " +
+ "volume matches with volume parameter in former config, it is set " +
+ "as reserved space. If not it fall backs to the latter config.",
+ HDDS_DATANODE_DIR_DU_RESERVED,
HDDS_DATANODE_DIR_DU_RESERVED_PERCENT);
+ }
+
+ // 1. If hdds.datanode.dir.du.reserved is set for a volume then make it
+ // as the reserved bytes.
Collection<String> reserveList = conf.getTrimmedStringCollection(
HDDS_DATANODE_DIR_DU_RESERVED);
for (String reserve : reserveList) {
@@ -149,12 +161,26 @@ public final class VolumeInfo {
StorageSize size = StorageSize.parse(words[1].trim());
return (long) size.getUnit().toBytes(size.getValue());
} catch (Exception e) {
- LOG.error("Failed to parse StorageSize:{}", words[1].trim(), e);
- return 0;
+ LOG.error("Failed to parse StorageSize: {}", words[1].trim(), e);
+ break;
}
}
}
+ // 2. If hdds.datanode.dir.du.reserved not set and
+ // hdds.datanode.dir.du.reserved.percent is set, fall back to this config.
+ if (conf.isConfigured(HDDS_DATANODE_DIR_DU_RESERVED_PERCENT)) {
+ float percentage = conf.getFloat(HDDS_DATANODE_DIR_DU_RESERVED_PERCENT,
+ HDDS_DATANODE_DIR_DU_RESERVED_PERCENT_DEFAULT);
+ if (0 <= percentage && percentage <= 1) {
+ return (long) Math.ceil(this.usage.getCapacity() * percentage);
+ }
+ //If it comes here then the percentage is not between 0-1.
+ LOG.error("The value of {} should be between 0 to 1. Defaulting to 0.",
+ HDDS_DATANODE_DIR_DU_RESERVED_PERCENT);
+ }
+
+ //Both configs are not set, return 0.
return 0;
}
@@ -183,8 +209,9 @@ public final class VolumeInfo {
SpaceUsageCheckParams checkParams =
usageCheckFactory.paramsFor(root);
+ this.usage = new VolumeUsage(checkParams);
this.reservedInBytes = getReserved(b.conf);
- this.usage = new VolumeUsage(checkParams, reservedInBytes);
+ this.usage.setReserved(reservedInBytes);
}
public long getCapacity() {
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/VolumeUsage.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/VolumeUsage.java
index fe12d4be9c..2d21c8f8ad 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/VolumeUsage.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/VolumeUsage.java
@@ -30,10 +30,9 @@ public class VolumeUsage implements SpaceUsageSource {
private final CachingSpaceUsageSource source;
private boolean shutdownComplete;
- private final long reservedInBytes;
+ private long reservedInBytes;
- VolumeUsage(SpaceUsageCheckParams checkParams, long reservedInBytes) {
- this.reservedInBytes = reservedInBytes;
+ VolumeUsage(SpaceUsageCheckParams checkParams) {
source = new CachingSpaceUsageSource(checkParams);
start(); // TODO should start only on demand
}
@@ -98,4 +97,8 @@ public class VolumeUsage implements SpaceUsageSource {
public void refreshNow() {
source.refreshNow();
}
+
+ public void setReserved(long reserved) {
+ this.reservedInBytes = reserved;
+ }
}
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/volume/TestReservedVolumeSpace.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/volume/TestReservedVolumeSpace.java
new file mode 100644
index 0000000000..471a9a750f
--- /dev/null
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/volume/TestReservedVolumeSpace.java
@@ -0,0 +1,149 @@
+/**
+ * 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.hadoop.ozone.container.common.volume;
+
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.fs.MockSpaceUsageCheckFactory;
+import org.apache.hadoop.hdds.scm.ScmConfigKeys;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.util.UUID;
+
+import static
org.apache.hadoop.hdds.scm.ScmConfigKeys.HDDS_DATANODE_DIR_DU_RESERVED_PERCENT;
+import static
org.apache.hadoop.hdds.scm.ScmConfigKeys.HDDS_DATANODE_DIR_DU_RESERVED_PERCENT_DEFAULT;
+
+/**
+ * To test the reserved volume space.
+ */
+public class TestReservedVolumeSpace {
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+ private static final String DATANODE_UUID = UUID.randomUUID().toString();
+ private HddsVolume.Builder volumeBuilder;
+
+ @Before
+ public void setup() throws Exception {
+ volumeBuilder = new HddsVolume.Builder(folder.getRoot().getPath())
+ .datanodeUuid(DATANODE_UUID)
+ .usageCheckFactory(MockSpaceUsageCheckFactory.NONE);
+ }
+
+ /**
+ * Test reserved capacity with respect to the percentage of actual capacity.
+ * @throws Exception
+ */
+ @Test
+ public void testVolumeCapacityAfterReserve() throws Exception {
+ OzoneConfiguration conf = new OzoneConfiguration();
+ conf.set(HDDS_DATANODE_DIR_DU_RESERVED_PERCENT, "0.3");
+ HddsVolume hddsVolume = volumeBuilder.conf(conf).build();
+ //Reserving
+ float percentage = conf.getFloat(HDDS_DATANODE_DIR_DU_RESERVED_PERCENT,
+ HDDS_DATANODE_DIR_DU_RESERVED_PERCENT_DEFAULT);
+
+ long volumeCapacity = hddsVolume.getCapacity();
+ //Gets the actual total capacity
+ long totalCapacity = hddsVolume.getVolumeInfo()
+ .getUsageForTesting().getCapacity();
+ long reservedCapacity = hddsVolume.getVolumeInfo().getReservedInBytes();
+ //Volume Capacity with Reserved
+ long volumeCapacityReserved = totalCapacity - reservedCapacity;
+
+ long reservedFromVolume = hddsVolume.getVolumeInfo().getReservedInBytes();
+ long reservedCalculated = (long) Math.ceil(totalCapacity * percentage);
+
+ Assert.assertEquals(reservedFromVolume, reservedCalculated);
+ Assert.assertEquals(volumeCapacity, volumeCapacityReserved);
+ }
+
+ /**
+ * When both configs are set, hdds.datanode.dir.du.reserved is set
+ * if the volume matches with volume in config parameter.
+ * @throws Exception
+ */
+ @Test
+ public void testReservedWhenBothConfigSet() throws Exception {
+ OzoneConfiguration conf = new OzoneConfiguration();
+ conf.set(HDDS_DATANODE_DIR_DU_RESERVED_PERCENT, "0.3");
+ conf.set(ScmConfigKeys.HDDS_DATANODE_DIR_DU_RESERVED,
+ folder.getRoot() + ":500B");
+ HddsVolume hddsVolume = volumeBuilder.conf(conf).build();
+
+ long reservedFromVolume = hddsVolume.getVolumeInfo().getReservedInBytes();
+ Assert.assertEquals(reservedFromVolume, 500);
+ }
+
+ @Test
+ public void testReservedToZeroWhenBothConfigNotSet() throws Exception {
+ OzoneConfiguration conf = new OzoneConfiguration();
+ HddsVolume hddsVolume = volumeBuilder.conf(conf).build();
+
+ long reservedFromVolume = hddsVolume.getVolumeInfo().getReservedInBytes();
+ Assert.assertEquals(reservedFromVolume, 0);
+ }
+
+ @Test
+ public void testFallbackToPercentConfig() throws Exception {
+ OzoneConfiguration conf = new OzoneConfiguration();
+ conf.set(HDDS_DATANODE_DIR_DU_RESERVED_PERCENT, "0.3");
+ //Setting config for different volume, hence fallback happens
+ conf.set(ScmConfigKeys.HDDS_DATANODE_DIR_DU_RESERVED,
+ temp.getRoot() + ":500B");
+ HddsVolume hddsVolume = volumeBuilder.conf(conf).build();
+
+ long reservedFromVolume = hddsVolume.getVolumeInfo().getReservedInBytes();
+ Assert.assertNotEquals(reservedFromVolume, 0);
+
+ long totalCapacity = hddsVolume.getVolumeInfo()
+ .getUsageForTesting().getCapacity();
+ float percentage = conf.getFloat(HDDS_DATANODE_DIR_DU_RESERVED_PERCENT,
+ HDDS_DATANODE_DIR_DU_RESERVED_PERCENT_DEFAULT);
+ long reservedCalculated = (long) Math.ceil(totalCapacity * percentage);
+ Assert.assertEquals(reservedFromVolume, reservedCalculated);
+ }
+
+ @Test
+ public void testInvalidConfig() throws Exception {
+ OzoneConfiguration conf1 = new OzoneConfiguration();
+
+ // 500C doesn't match with any Storage Unit
+ conf1.set(ScmConfigKeys.HDDS_DATANODE_DIR_DU_RESERVED,
+ folder.getRoot() + ":500C");
+ HddsVolume hddsVolume1 = volumeBuilder.conf(conf1).build();
+
+ long reservedFromVolume1 =
hddsVolume1.getVolumeInfo().getReservedInBytes();
+ Assert.assertEquals(reservedFromVolume1, 0);
+
+ OzoneConfiguration conf2 = new OzoneConfiguration();
+
+ //Should be between 0-1.
+ conf2.set(HDDS_DATANODE_DIR_DU_RESERVED_PERCENT, "20");
+ HddsVolume hddsVolume2 = volumeBuilder.conf(conf2).build();
+
+ long reservedFromVolume2 =
hddsVolume2.getVolumeInfo().getReservedInBytes();
+ Assert.assertEquals(reservedFromVolume2, 0);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]