HDDS-262. Send SCM healthy and failed volumes in the heartbeat. Contributed by Bharat Viswanadham.
This commit is contained in:
parent
2ced3efe94
commit
16f9aee5f5
@ -37,6 +37,7 @@
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HddsVolume represents volume in a datanode. {@link VolumeSet} maitains a
|
* HddsVolume represents volume in a datanode. {@link VolumeSet} maitains a
|
||||||
@ -84,6 +85,7 @@ public static class Builder {
|
|||||||
|
|
||||||
private String datanodeUuid;
|
private String datanodeUuid;
|
||||||
private String clusterID;
|
private String clusterID;
|
||||||
|
private boolean failedVolume = false;
|
||||||
|
|
||||||
public Builder(String rootDirStr) {
|
public Builder(String rootDirStr) {
|
||||||
this.volumeRootStr = rootDirStr;
|
this.volumeRootStr = rootDirStr;
|
||||||
@ -114,12 +116,21 @@ public Builder clusterID(String cid) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is added just to create failed volume objects, which will be used
|
||||||
|
// to create failed HddsVolume objects in the case of any exceptions caused
|
||||||
|
// during creating HddsVolume object.
|
||||||
|
public Builder failedVolume(boolean failed) {
|
||||||
|
this.failedVolume = failed;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public HddsVolume build() throws IOException {
|
public HddsVolume build() throws IOException {
|
||||||
return new HddsVolume(this);
|
return new HddsVolume(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private HddsVolume(Builder b) throws IOException {
|
private HddsVolume(Builder b) throws IOException {
|
||||||
|
if (!b.failedVolume) {
|
||||||
StorageLocation location = StorageLocation.parse(b.volumeRootStr);
|
StorageLocation location = StorageLocation.parse(b.volumeRootStr);
|
||||||
hddsRootDir = new File(location.getUri().getPath(), HDDS_VOLUME_DIR);
|
hddsRootDir = new File(location.getUri().getPath(), HDDS_VOLUME_DIR);
|
||||||
this.state = VolumeState.NOT_INITIALIZED;
|
this.state = VolumeState.NOT_INITIALIZED;
|
||||||
@ -137,6 +148,15 @@ private HddsVolume(Builder b) throws IOException {
|
|||||||
b.storageType + " and capacity : " + volumeInfo.getCapacity());
|
b.storageType + " and capacity : " + volumeInfo.getCapacity());
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
|
} else {
|
||||||
|
// Builder is called with failedVolume set, so create a failed volume
|
||||||
|
// HddsVolumeObject.
|
||||||
|
hddsRootDir = new File(b.volumeRootStr);
|
||||||
|
volumeIOStats = null;
|
||||||
|
volumeInfo = null;
|
||||||
|
storageID = UUID.randomUUID().toString();
|
||||||
|
state = VolumeState.FAILED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public VolumeInfo getVolumeInfo() {
|
public VolumeInfo getVolumeInfo() {
|
||||||
@ -285,8 +305,11 @@ public File getHddsRootDir() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public StorageType getStorageType() {
|
public StorageType getStorageType() {
|
||||||
|
if(volumeInfo != null) {
|
||||||
return volumeInfo.getStorageType();
|
return volumeInfo.getStorageType();
|
||||||
}
|
}
|
||||||
|
return StorageType.DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
public String getStorageID() {
|
public String getStorageID() {
|
||||||
return storageID;
|
return storageID;
|
||||||
@ -313,12 +336,18 @@ public VolumeState getStorageState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getCapacity() throws IOException {
|
public long getCapacity() throws IOException {
|
||||||
|
if(volumeInfo != null) {
|
||||||
return volumeInfo.getCapacity();
|
return volumeInfo.getCapacity();
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public long getAvailable() throws IOException {
|
public long getAvailable() throws IOException {
|
||||||
|
if(volumeInfo != null) {
|
||||||
return volumeInfo.getAvailable();
|
return volumeInfo.getAvailable();
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public void setState(VolumeState state) {
|
public void setState(VolumeState state) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
@ -334,13 +363,17 @@ public VolumeIOStats getVolumeIOStats() {
|
|||||||
|
|
||||||
public void failVolume() {
|
public void failVolume() {
|
||||||
setState(VolumeState.FAILED);
|
setState(VolumeState.FAILED);
|
||||||
|
if (volumeInfo != null) {
|
||||||
volumeInfo.shutdownUsageThread();
|
volumeInfo.shutdownUsageThread();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
this.state = VolumeState.NON_EXISTENT;
|
this.state = VolumeState.NON_EXISTENT;
|
||||||
|
if (volumeInfo != null) {
|
||||||
volumeInfo.shutdownUsageThread();
|
volumeInfo.shutdownUsageThread();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VolumeState represents the different states a HddsVolume can be in.
|
* VolumeState represents the different states a HddsVolume can be in.
|
||||||
@ -368,6 +401,8 @@ public enum VolumeState {
|
|||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void setScmUsageForTesting(GetSpaceUsed scmUsageForTest) {
|
public void setScmUsageForTesting(GetSpaceUsed scmUsageForTest) {
|
||||||
|
if (volumeInfo != null) {
|
||||||
volumeInfo.setScmUsageForTesting(scmUsageForTest);
|
volumeInfo.setScmUsageForTesting(scmUsageForTest);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,7 @@ public class VolumeSet {
|
|||||||
* mutually exclusive.
|
* mutually exclusive.
|
||||||
*/
|
*/
|
||||||
private Map<String, HddsVolume> failedVolumeMap;
|
private Map<String, HddsVolume> failedVolumeMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link VolumeSet#volumeStateMap} maintains a list of active volumes per
|
* {@link VolumeSet#volumeStateMap} maintains a list of active volumes per
|
||||||
* StorageType.
|
* StorageType.
|
||||||
@ -95,12 +96,12 @@ public class VolumeSet {
|
|||||||
private Runnable shutdownHook;
|
private Runnable shutdownHook;
|
||||||
|
|
||||||
public VolumeSet(String dnUuid, Configuration conf)
|
public VolumeSet(String dnUuid, Configuration conf)
|
||||||
throws DiskOutOfSpaceException {
|
throws IOException {
|
||||||
this(dnUuid, null, conf);
|
this(dnUuid, null, conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public VolumeSet(String dnUuid, String clusterID, Configuration conf)
|
public VolumeSet(String dnUuid, String clusterID, Configuration conf)
|
||||||
throws DiskOutOfSpaceException {
|
throws IOException {
|
||||||
this.datanodeUuid = dnUuid;
|
this.datanodeUuid = dnUuid;
|
||||||
this.clusterID = clusterID;
|
this.clusterID = clusterID;
|
||||||
this.conf = conf;
|
this.conf = conf;
|
||||||
@ -120,7 +121,7 @@ public VolumeSet(String dnUuid, String clusterID, Configuration conf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add DN volumes configured through ConfigKeys to volumeMap.
|
// Add DN volumes configured through ConfigKeys to volumeMap.
|
||||||
private void initializeVolumeSet() throws DiskOutOfSpaceException {
|
private void initializeVolumeSet() throws IOException {
|
||||||
volumeMap = new ConcurrentHashMap<>();
|
volumeMap = new ConcurrentHashMap<>();
|
||||||
failedVolumeMap = new ConcurrentHashMap<>();
|
failedVolumeMap = new ConcurrentHashMap<>();
|
||||||
volumeStateMap = new EnumMap<>(StorageType.class);
|
volumeStateMap = new EnumMap<>(StorageType.class);
|
||||||
@ -153,6 +154,9 @@ private void initializeVolumeSet() throws DiskOutOfSpaceException {
|
|||||||
LOG.info("Added Volume : {} to VolumeSet",
|
LOG.info("Added Volume : {} to VolumeSet",
|
||||||
hddsVolume.getHddsRootDir().getPath());
|
hddsVolume.getHddsRootDir().getPath());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
HddsVolume volume = new HddsVolume.Builder(locationString)
|
||||||
|
.failedVolume(true).build();
|
||||||
|
failedVolumeMap.put(locationString, volume);
|
||||||
LOG.error("Failed to parse the storage location: " + locationString, e);
|
LOG.error("Failed to parse the storage location: " + locationString, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -337,11 +341,12 @@ public Map<StorageType, List<HddsVolume>> getVolumeStateMap() {
|
|||||||
public StorageContainerDatanodeProtocolProtos.NodeReportProto getNodeReport()
|
public StorageContainerDatanodeProtocolProtos.NodeReportProto getNodeReport()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
boolean failed;
|
boolean failed;
|
||||||
StorageLocationReport[] reports =
|
StorageLocationReport[] reports = new StorageLocationReport[volumeMap
|
||||||
new StorageLocationReport[volumeMap.size()];
|
.size() + failedVolumeMap.size()];
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
|
HddsVolume hddsVolume;
|
||||||
for (Map.Entry<String, HddsVolume> entry : volumeMap.entrySet()) {
|
for (Map.Entry<String, HddsVolume> entry : volumeMap.entrySet()) {
|
||||||
HddsVolume hddsVolume = entry.getValue();
|
hddsVolume = entry.getValue();
|
||||||
VolumeInfo volumeInfo = hddsVolume.getVolumeInfo();
|
VolumeInfo volumeInfo = hddsVolume.getVolumeInfo();
|
||||||
long scmUsed = 0;
|
long scmUsed = 0;
|
||||||
long remaining = 0;
|
long remaining = 0;
|
||||||
@ -370,6 +375,17 @@ public StorageContainerDatanodeProtocolProtos.NodeReportProto getNodeReport()
|
|||||||
StorageLocationReport r = builder.build();
|
StorageLocationReport r = builder.build();
|
||||||
reports[counter++] = r;
|
reports[counter++] = r;
|
||||||
}
|
}
|
||||||
|
for (Map.Entry<String, HddsVolume> entry : failedVolumeMap.entrySet()) {
|
||||||
|
hddsVolume = entry.getValue();
|
||||||
|
StorageLocationReport.Builder builder = StorageLocationReport
|
||||||
|
.newBuilder();
|
||||||
|
builder.setStorageLocation(hddsVolume.getHddsRootDir()
|
||||||
|
.getAbsolutePath()).setId(hddsVolume.getStorageID()).setFailed(true)
|
||||||
|
.setCapacity(0).setRemaining(0).setScmUsed(0).setStorageType(
|
||||||
|
hddsVolume.getStorageType());
|
||||||
|
StorageLocationReport r = builder.build();
|
||||||
|
reports[counter++] = r;
|
||||||
|
}
|
||||||
NodeReportProto.Builder nrb = NodeReportProto.newBuilder();
|
NodeReportProto.Builder nrb = NodeReportProto.newBuilder();
|
||||||
for (int i = 0; i < reports.length; i++) {
|
for (int i = 0; i < reports.length; i++) {
|
||||||
nrb.addStorageReport(reports[i].getProtoBufMessage());
|
nrb.addStorageReport(reports[i].getProtoBufMessage());
|
||||||
|
@ -27,8 +27,10 @@
|
|||||||
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||||
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
||||||
import org.apache.hadoop.ozone.container.common.utils.HddsVolumeUtil;
|
import org.apache.hadoop.ozone.container.common.utils.HddsVolumeUtil;
|
||||||
|
import org.apache.hadoop.test.GenericTestUtils;
|
||||||
import org.apache.hadoop.test.GenericTestUtils.LogCapturer;
|
import org.apache.hadoop.test.GenericTestUtils.LogCapturer;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.hdds.scm.ScmConfigKeys.HDDS_DATANODE_DIR_KEY;
|
||||||
import static org.apache.hadoop.ozone.container.common.volume.HddsVolume
|
import static org.apache.hadoop.ozone.container.common.volume.HddsVolume
|
||||||
.HDDS_VOLUME_DIR;
|
.HDDS_VOLUME_DIR;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@ -82,14 +84,16 @@ public void setup() throws Exception {
|
|||||||
@After
|
@After
|
||||||
public void shutdown() throws IOException {
|
public void shutdown() throws IOException {
|
||||||
// Delete the hdds volume root dir
|
// Delete the hdds volume root dir
|
||||||
List<HddsVolume> volumes = new ArrayList<>();
|
List<HddsVolume> hddsVolumes = new ArrayList<>();
|
||||||
volumes.addAll(volumeSet.getVolumesList());
|
hddsVolumes.addAll(volumeSet.getVolumesList());
|
||||||
volumes.addAll(volumeSet.getFailedVolumesList());
|
hddsVolumes.addAll(volumeSet.getFailedVolumesList());
|
||||||
|
|
||||||
for (HddsVolume volume : volumes) {
|
for (HddsVolume volume : hddsVolumes) {
|
||||||
FileUtils.deleteDirectory(volume.getHddsRootDir());
|
FileUtils.deleteDirectory(volume.getHddsRootDir());
|
||||||
}
|
}
|
||||||
volumeSet.shutdown();
|
volumeSet.shutdown();
|
||||||
|
|
||||||
|
FileUtil.fullyDelete(new File(baseDir));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkVolumeExistsInVolumeSet(String volume) {
|
private boolean checkVolumeExistsInVolumeSet(String volume) {
|
||||||
@ -222,6 +226,29 @@ public void testShutdown() throws Exception {
|
|||||||
// Do Nothing. Exception is expected.
|
// Do Nothing. Exception is expected.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFailVolumes() throws Exception{
|
||||||
|
VolumeSet volSet = null;
|
||||||
|
File readOnlyVolumePath = new File(baseDir);
|
||||||
|
//Set to readonly, so that this volume will be failed
|
||||||
|
readOnlyVolumePath.setReadOnly();
|
||||||
|
File volumePath = GenericTestUtils.getRandomizedTestDir();
|
||||||
|
OzoneConfiguration ozoneConfig = new OzoneConfiguration();
|
||||||
|
ozoneConfig.set(HDDS_DATANODE_DIR_KEY, readOnlyVolumePath.getAbsolutePath()
|
||||||
|
+ "," + volumePath.getAbsolutePath());
|
||||||
|
volSet = new VolumeSet(UUID.randomUUID().toString(), ozoneConfig);
|
||||||
|
assertTrue(volSet.getFailedVolumesList().size() == 1);
|
||||||
|
assertEquals(readOnlyVolumePath, volSet.getFailedVolumesList().get(0)
|
||||||
|
.getHddsRootDir());
|
||||||
|
|
||||||
|
//Set back to writable
|
||||||
|
try {
|
||||||
|
readOnlyVolumePath.setWritable(true);
|
||||||
|
} finally {
|
||||||
|
FileUtil.fullyDelete(volumePath);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user