HDFS-15028. Keep the capacity of volume and reduce a system call. Contributed by Yang Yun.
Signed-off-by: Masatake Iwasaki <iwasakims@apache.org>
This commit is contained in:
parent
ecd461f940
commit
11cd5b6e39
|
@ -153,6 +153,9 @@ public class DFSConfigKeys extends CommonConfigurationKeys {
|
||||||
"dfs.datanode.non.local.lazy.persist";
|
"dfs.datanode.non.local.lazy.persist";
|
||||||
public static final boolean DFS_DATANODE_NON_LOCAL_LAZY_PERSIST_DEFAULT =
|
public static final boolean DFS_DATANODE_NON_LOCAL_LAZY_PERSIST_DEFAULT =
|
||||||
false;
|
false;
|
||||||
|
public static final String DFS_DATANODE_FIXED_VOLUME_SIZE_KEY =
|
||||||
|
"dfs.datanode.fixed.volume.size";
|
||||||
|
public static final boolean DFS_DATANODE_FIXED_VOLUME_SIZE_DEFAULT = false;
|
||||||
|
|
||||||
// This setting is for testing/internal use only.
|
// This setting is for testing/internal use only.
|
||||||
public static final String DFS_DATANODE_DUPLICATE_REPLICA_DELETION = "dfs.datanode.duplicate.replica.deletion";
|
public static final String DFS_DATANODE_DUPLICATE_REPLICA_DELETION = "dfs.datanode.duplicate.replica.deletion";
|
||||||
|
|
|
@ -120,6 +120,7 @@ public class FsVolumeImpl implements FsVolumeSpi {
|
||||||
private final File currentDir; // <StorageDirectory>/current
|
private final File currentDir; // <StorageDirectory>/current
|
||||||
private final DF usage;
|
private final DF usage;
|
||||||
private final ReservedSpaceCalculator reserved;
|
private final ReservedSpaceCalculator reserved;
|
||||||
|
private long cachedCapacity;
|
||||||
private CloseableReferenceCount reference = new CloseableReferenceCount();
|
private CloseableReferenceCount reference = new CloseableReferenceCount();
|
||||||
|
|
||||||
// Disk space reserved for blocks (RBW or Re-replicating) open for write.
|
// Disk space reserved for blocks (RBW or Re-replicating) open for write.
|
||||||
|
@ -166,9 +167,16 @@ public class FsVolumeImpl implements FsVolumeSpi {
|
||||||
if (this.usage != null) {
|
if (this.usage != null) {
|
||||||
reserved = new ReservedSpaceCalculator.Builder(conf)
|
reserved = new ReservedSpaceCalculator.Builder(conf)
|
||||||
.setUsage(this.usage).setStorageType(storageType).build();
|
.setUsage(this.usage).setStorageType(storageType).build();
|
||||||
|
boolean fixedSizeVolume = conf.getBoolean(
|
||||||
|
DFSConfigKeys.DFS_DATANODE_FIXED_VOLUME_SIZE_KEY,
|
||||||
|
DFSConfigKeys.DFS_DATANODE_FIXED_VOLUME_SIZE_DEFAULT);
|
||||||
|
if (fixedSizeVolume) {
|
||||||
|
cachedCapacity = this.usage.getCapacity();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
reserved = null;
|
reserved = null;
|
||||||
LOG.warn("Setting reserved to null as usage is null");
|
LOG.warn("Setting reserved to null as usage is null");
|
||||||
|
cachedCapacity = -1;
|
||||||
}
|
}
|
||||||
if (currentDir != null) {
|
if (currentDir != null) {
|
||||||
File parent = currentDir.getParentFile();
|
File parent = currentDir.getParentFile();
|
||||||
|
@ -402,7 +410,12 @@ public class FsVolumeImpl implements FsVolumeSpi {
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public long getCapacity() {
|
public long getCapacity() {
|
||||||
if (configuredCapacity < 0L) {
|
if (configuredCapacity < 0L) {
|
||||||
long remaining = usage.getCapacity() - getReserved();
|
long remaining;
|
||||||
|
if (cachedCapacity > 0L) {
|
||||||
|
remaining = cachedCapacity - getReserved();
|
||||||
|
} else {
|
||||||
|
remaining = usage.getCapacity() - getReserved();
|
||||||
|
}
|
||||||
return Math.max(remaining, 0L);
|
return Math.max(remaining, 0L);
|
||||||
}
|
}
|
||||||
return configuredCapacity;
|
return configuredCapacity;
|
||||||
|
|
|
@ -4405,6 +4405,16 @@
|
||||||
</description>
|
</description>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
|
<property>
|
||||||
|
<name>dfs.datanode.fixed.volume.size</name>
|
||||||
|
<value>false</value>
|
||||||
|
<description>
|
||||||
|
If false, call function getTotalSpace of File to get capacity of volume
|
||||||
|
during every heartbeat.
|
||||||
|
If true, cache the capacity when when the first call, and reuse it later.
|
||||||
|
</description>
|
||||||
|
</property>
|
||||||
|
|
||||||
<property>
|
<property>
|
||||||
<name>dfs.ha.fencing.methods</name>
|
<name>dfs.ha.fencing.methods</name>
|
||||||
<value></value>
|
<value></value>
|
||||||
|
|
|
@ -61,6 +61,8 @@ import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
public class TestFsVolumeList {
|
public class TestFsVolumeList {
|
||||||
|
@ -209,7 +211,7 @@ public class TestFsVolumeList {
|
||||||
/*
|
/*
|
||||||
* Lets have the example.
|
* Lets have the example.
|
||||||
* Capacity - 1000
|
* Capacity - 1000
|
||||||
* Reserved - 100
|
* Reserved - 100G
|
||||||
* DfsUsed - 200
|
* DfsUsed - 200
|
||||||
* Actual Non-DfsUsed - 300 -->(expected)
|
* Actual Non-DfsUsed - 300 -->(expected)
|
||||||
* ReservedForReplicas - 50
|
* ReservedForReplicas - 50
|
||||||
|
@ -403,4 +405,51 @@ public class TestFsVolumeList {
|
||||||
threadPool1, threadPool2);
|
threadPool1, threadPool2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCachedVolumeCapacity() throws IOException {
|
||||||
|
conf.setBoolean(DFSConfigKeys.DFS_DATANODE_FIXED_VOLUME_SIZE_KEY,
|
||||||
|
DFSConfigKeys.DFS_DATANODE_FIXED_VOLUME_SIZE_DEFAULT);
|
||||||
|
|
||||||
|
long capacity = 4000L;
|
||||||
|
DF usage = mock(DF.class);
|
||||||
|
when(usage.getCapacity()).thenReturn(capacity);
|
||||||
|
|
||||||
|
FsVolumeImpl volumeChanged = new FsVolumeImplBuilder()
|
||||||
|
.setConf(conf)
|
||||||
|
.setDataset(dataset)
|
||||||
|
.setStorageID("storage-id")
|
||||||
|
.setStorageDirectory(new StorageDirectory(StorageLocation.parse(
|
||||||
|
"[RAM_DISK]volume-changed")))
|
||||||
|
.setUsage(usage)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
int callTimes = 5;
|
||||||
|
for(int i = 0; i < callTimes; i++) {
|
||||||
|
assertEquals(capacity, volumeChanged.getCapacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
verify(usage, times(callTimes)).getCapacity();
|
||||||
|
|
||||||
|
conf.setBoolean(DFSConfigKeys.DFS_DATANODE_FIXED_VOLUME_SIZE_KEY, true);
|
||||||
|
FsVolumeImpl volumeFixed = new FsVolumeImplBuilder()
|
||||||
|
.setConf(conf)
|
||||||
|
.setDataset(dataset)
|
||||||
|
.setStorageID("storage-id")
|
||||||
|
.setStorageDirectory(new StorageDirectory(StorageLocation.parse(
|
||||||
|
"[RAM_DISK]volume-fixed")))
|
||||||
|
.setUsage(usage)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
for(int i = 0; i < callTimes; i++) {
|
||||||
|
assertEquals(capacity, volumeFixed.getCapacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
// reuse the capacity for fixed sized volume, only call one time
|
||||||
|
// getCapacity of DF
|
||||||
|
verify(usage, times(callTimes+1)).getCapacity();
|
||||||
|
|
||||||
|
conf.setBoolean(DFSConfigKeys.DFS_DATANODE_FIXED_VOLUME_SIZE_KEY,
|
||||||
|
DFSConfigKeys.DFS_DATANODE_FIXED_VOLUME_SIZE_DEFAULT);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue