Skip to content

Commit

Permalink
HDDS-11135. [hsync] Replace expensive VolumeUsage.getMinVolumeFreeSpa…
Browse files Browse the repository at this point in the history
…ce() (#6930)

Co-authored-by: Duong Nguyen <duongnt.is@gmail.com>
  • Loading branch information
jojochuang and duongkame authored Jul 16, 2024
1 parent d8ea69d commit 6c6dc43
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ public class HddsDispatcher implements ContainerDispatcher, Auditor {
private ContainerMetrics metrics;
private final TokenVerifier tokenVerifier;
private long slowOpThresholdMs;
private VolumeUsage.MinFreeSpaceCalculator freeSpaceCalculator;

/**
* Constructs an OzoneContainer that receives calls from
Expand Down Expand Up @@ -147,6 +148,7 @@ public HddsDispatcher(ConfigurationSource config, ContainerSet contSet,
LOG,
HddsUtils::processForDebug,
HddsUtils::processForDebug);
this.freeSpaceCalculator = new VolumeUsage.MinFreeSpaceCalculator(conf);
}

@Override
Expand Down Expand Up @@ -612,7 +614,7 @@ private boolean isVolumeFull(Container container) {
volume.getCurrentUsage();
long volumeCapacity = precomputedVolumeSpace.getCapacity();
long volumeFreeSpaceToSpare =
VolumeUsage.getMinVolumeFreeSpace(conf, volumeCapacity);
freeSpaceCalculator.get(volumeCapacity);
long volumeFree = precomputedVolumeSpace.getAvailable();
long volumeCommitted = volume.getCommittedBytes();
long volumeAvailable = volumeFree - volumeCommitted;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ public StorageReportProto getProtoBufMessage(ConfigurationSource conf)
.setStorageLocation(getStorageLocation())
.setFailed(isFailed())
.setFreeSpaceToSpare(conf != null ?
VolumeUsage.getMinVolumeFreeSpace(conf, getCapacity()) : 0)
new VolumeUsage.MinFreeSpaceCalculator(conf).get(getCapacity()) : 0)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public boolean test(HddsVolume vol) {
long committed = vol.getCommittedBytes();
long available = free - committed;
long volumeFreeSpaceToSpare =
VolumeUsage.getMinVolumeFreeSpace(vol.getConf(), volumeCapacity);
new VolumeUsage.MinFreeSpaceCalculator(vol.getConf()).get(volumeCapacity);
boolean hasEnoughSpace = VolumeUsage.hasVolumeEnoughSpace(free, committed,
requiredSpace, volumeFreeSpaceToSpare);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,37 +140,55 @@ public long getReservedBytes() {
}

/**
* If 'hdds.datanode.volume.min.free.space' is defined,
* it will be honored first. If it is not defined and
* 'hdds.datanode.volume.min.free.space.' is defined,it will honor this
* else it will fall back to 'hdds.datanode.volume.min.free.space.default'
* Convenience class to calculate minimum free space.
*/
public static long getMinVolumeFreeSpace(ConfigurationSource conf,
long capacity) {
if (conf.isConfigured(
HDDS_DATANODE_VOLUME_MIN_FREE_SPACE) && conf.isConfigured(
HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_PERCENT)) {
LOG.error(
"Both {} and {} are set. Set either one, not both. If both are set,"
+ "it will use default value which is {} as min free space",
HDDS_DATANODE_VOLUME_MIN_FREE_SPACE,
HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_PERCENT,
HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_DEFAULT);
}

if (conf.isConfigured(HDDS_DATANODE_VOLUME_MIN_FREE_SPACE)) {
return (long) conf.getStorageSize(HDDS_DATANODE_VOLUME_MIN_FREE_SPACE,
public static class MinFreeSpaceCalculator {
private final boolean minFreeSpaceConfigured;
private final boolean minFreeSpacePercentConfigured;
private final long freeSpace;
private float freeSpacePercent;
private final long defaultFreeSpace;
public MinFreeSpaceCalculator(ConfigurationSource conf) {
// cache these values to avoid repeated lookups
minFreeSpaceConfigured = conf.isConfigured(HDDS_DATANODE_VOLUME_MIN_FREE_SPACE);
minFreeSpacePercentConfigured = conf.isConfigured(HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_PERCENT);
freeSpace = (long)conf.getStorageSize(HDDS_DATANODE_VOLUME_MIN_FREE_SPACE,
HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_DEFAULT, StorageUnit.BYTES);
} else if (conf.isConfigured(HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_PERCENT)) {
float volumeMinFreeSpacePercent = Float.parseFloat(
conf.get(HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_PERCENT));
return (long) (capacity * volumeMinFreeSpacePercent);
if (minFreeSpacePercentConfigured) {
freeSpacePercent = Float.parseFloat(
conf.get(HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_PERCENT));
}
StorageSize measure = StorageSize.parse(HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_DEFAULT);
double byteValue = measure.getUnit().toBytes(measure.getValue());
defaultFreeSpace = (long)StorageUnit.BYTES.fromBytes(byteValue);
}
// either properties are not configured,then return
// HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_DEFAULT,
return (long) conf.getStorageSize(HDDS_DATANODE_VOLUME_MIN_FREE_SPACE,
HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_DEFAULT, StorageUnit.BYTES);

/**
* If 'hdds.datanode.volume.min.free.space' is defined,
* it will be honored first. If it is not defined and
* 'hdds.datanode.volume.min.free.space' is defined, it will honor this
* else it will fall back to 'hdds.datanode.volume.min.free.space.default'
*/
public long get(long capacity) {
if (minFreeSpaceConfigured && minFreeSpacePercentConfigured) {
LOG.error(
"Both {} and {} are set. Set either one, not both. If both are set,"
+ "it will use default value which is {} as min free space",
HDDS_DATANODE_VOLUME_MIN_FREE_SPACE,
HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_PERCENT,
HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_DEFAULT);
return defaultFreeSpace;
}

if (minFreeSpaceConfigured) {
return freeSpace;
} else if (minFreeSpacePercentConfigured) {
return (long) (capacity * freeSpacePercent);
}
// either properties are not configured,then return
// HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_DEFAULT
return defaultFreeSpace;
}
}

public static boolean hasVolumeEnoughSpace(long volumeAvailableSpace,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

package org.apache.hadoop.ozone.container.common.volume;

import org.apache.hadoop.conf.StorageUnit;
import org.apache.hadoop.hdds.HddsConfigKeys;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.fs.MockSpaceUsageCheckFactory;
import org.apache.hadoop.hdds.scm.ScmConfigKeys;
Expand All @@ -30,6 +32,8 @@
import java.nio.file.Path;
import java.util.UUID;

import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_DATANODE_VOLUME_MIN_FREE_SPACE;
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_PERCENT;
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;
import static org.junit.jupiter.api.Assertions.assertEquals;
Expand Down Expand Up @@ -178,6 +182,28 @@ public void testPathsCanonicalized() throws Exception {
assertEquals(500, reservedFromVolume);
}

@Test
public void testMinFreeSpaceCalculator() throws Exception {
OzoneConfiguration conf = new OzoneConfiguration();
double minSpace = 100.0;
conf.setStorageSize(HddsConfigKeys.HDDS_DATANODE_VOLUME_MIN_FREE_SPACE,
minSpace, StorageUnit.BYTES);
VolumeUsage.MinFreeSpaceCalculator calc = new VolumeUsage.MinFreeSpaceCalculator(conf);
long capacity = 1000;
assertEquals(minSpace, calc.get(capacity));

conf.setFloat(HDDS_DATANODE_VOLUME_MIN_FREE_SPACE_PERCENT, 0.01f);
calc = new VolumeUsage.MinFreeSpaceCalculator(conf);
// default is 5GB
assertEquals(5L * 1024 * 1024 * 1024, calc.get(capacity));

// capacity * 1% = 10
conf.unset(HDDS_DATANODE_VOLUME_MIN_FREE_SPACE);
calc = new VolumeUsage.MinFreeSpaceCalculator(conf);
assertEquals(10, calc.get(capacity));
}


private long getExpectedDefaultReserved(HddsVolume volume) {
long totalCapacity = volume.getVolumeInfo().get().getUsageForTesting().realUsage().getCapacity();
return (long) Math.ceil(totalCapacity * HDDS_DATANODE_DIR_DU_RESERVED_PERCENT_DEFAULT);
Expand Down

0 comments on commit 6c6dc43

Please sign in to comment.