diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/HddsVolume.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/HddsVolume.java index a1e41ff9d73a..e817202846e5 100644 --- a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/HddsVolume.java +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/HddsVolume.java @@ -52,7 +52,7 @@ * Each hdds volume has its own VERSION file. The hdds volume will have one * clusterUuid directory for each SCM it is a part of (currently only one SCM is * supported). - * + *

* During DN startup, if the VERSION file exists, we verify that the * clusterID in the version file matches the clusterID from SCM. */ @@ -67,6 +67,7 @@ public class HddsVolume extends StorageVolume { private VolumeState state; private final VolumeIOStats volumeIOStats; + private final VolumeInfoMetrics volumeInfoMetrics; // VERSION file properties private String storageID; // id of the file system @@ -76,6 +77,9 @@ public class HddsVolume extends StorageVolume { private int layoutVersion; // layout version of the storage data private final AtomicLong committedBytes; // till Open containers become full + // Mentions the type of volume + private final VolumeType type = VolumeType.DATA_VOLUME; + /** * Builder for HddsVolume. */ @@ -115,6 +119,8 @@ private HddsVolume(Builder b) throws IOException { this.clusterID = b.clusterID; this.datanodeUuid = b.datanodeUuid; this.volumeIOStats = new VolumeIOStats(b.getVolumeRootStr()); + this.volumeInfoMetrics = + new VolumeInfoMetrics(b.getVolumeRootStr(), this); this.committedBytes = new AtomicLong(0); LOG.info("Creating HddsVolume: {} of storage type : {} capacity : {}", @@ -125,6 +131,7 @@ private HddsVolume(Builder b) throws IOException { // Builder is called with failedVolume set, so create a failed volume // HddsVolume Object. volumeIOStats = null; + volumeInfoMetrics = null; storageID = UUID.randomUUID().toString(); state = VolumeState.FAILED; committedBytes = null; @@ -136,6 +143,7 @@ private HddsVolume(Builder b) throws IOException { * Initializes the volume. * Creates the Version file if not present, * otherwise returns with IOException. + * * @throws IOException */ private void initialize() throws IOException { @@ -176,7 +184,7 @@ private VolumeState analyzeVolumeState() { if (!getStorageDir().isDirectory()) { // Volume Root exists but is not a directory. LOG.warn("Volume {} exists but is not a directory," - + " current volume state: {}.", + + " current volume state: {}.", getStorageDir().getPath(), VolumeState.INCONSISTENT); return VolumeState.INCONSISTENT; } @@ -188,7 +196,7 @@ private VolumeState analyzeVolumeState() { if (!getVersionFile().exists()) { // Volume Root is non empty but VERSION file does not exist. LOG.warn("VERSION file does not exist in volume {}," - + " current volume state: {}.", + + " current volume state: {}.", getStorageDir().getPath(), VolumeState.INCONSISTENT); return VolumeState.INCONSISTENT; } @@ -205,6 +213,7 @@ public void format(String cid) throws IOException { /** * Create Version File and write property fields into it. + * * @throws IOException */ private void createVersionFile() throws IOException { @@ -300,6 +309,10 @@ public int getLayoutVersion() { return layoutVersion; } + public VolumeType getType() { + return type; + } + public VolumeState getStorageState() { return state; } @@ -316,6 +329,10 @@ public VolumeIOStats getVolumeIOStats() { return volumeIOStats; } + public VolumeInfoMetrics getVolumeInfoStats() { + return volumeInfoMetrics; + } + @Override public void failVolume() { setState(VolumeState.FAILED); @@ -323,6 +340,9 @@ public void failVolume() { if (volumeIOStats != null) { volumeIOStats.unregister(); } + if (volumeInfoMetrics != null) { + volumeInfoMetrics.unregister(); + } } @Override @@ -332,19 +352,22 @@ public void shutdown() { if (volumeIOStats != null) { volumeIOStats.unregister(); } + if (volumeInfoMetrics != null) { + volumeInfoMetrics.unregister(); + } } /** * VolumeState represents the different states a HddsVolume can be in. * NORMAL => Volume can be used for storage * FAILED => Volume has failed due and can no longer be used for - * storing containers. + * storing containers. * NON_EXISTENT => Volume Root dir does not exist * INCONSISTENT => Volume Root dir is not empty but VERSION file is - * missing or Volume Root dir is not a directory + * missing or Volume Root dir is not a directory * NOT_FORMATTED => Volume Root exists but not formatted(no VERSION file) * NOT_INITIALIZED => VERSION file exists but has not been verified for - * correctness. + * correctness. */ public enum VolumeState { NORMAL, @@ -357,6 +380,7 @@ public enum VolumeState { /** * add "delta" bytes to committed space in the volume. + * * @param delta bytes to add to committed space counter * @return bytes of committed space */ @@ -366,9 +390,10 @@ public long incCommittedBytes(long delta) { /** * return the committed space in the volume. + * * @return bytes of committed space */ public long getCommittedBytes() { return committedBytes.get(); } -} +} \ No newline at end of file diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/MetadataVolume.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/MetadataVolume.java index c5532ffdbb41..bdedeff1659f 100644 --- a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/MetadataVolume.java +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/MetadataVolume.java @@ -27,10 +27,16 @@ */ public class MetadataVolume extends StorageVolume { + private final VolumeType type = VolumeType.META_VOLUME; + protected MetadataVolume(Builder b) throws IOException { super(b); } + public VolumeType getType() { + return type; + } + /** * Builder class for MetadataVolume. */ diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/VolumeInfoMetrics.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/VolumeInfoMetrics.java new file mode 100644 index 000000000000..21b9d2aaa6c9 --- /dev/null +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/VolumeInfoMetrics.java @@ -0,0 +1,137 @@ +/* + * 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.metrics2.MetricsSystem; +import org.apache.hadoop.metrics2.annotation.Metric; +import org.apache.hadoop.metrics2.annotation.Metrics; +import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; +import org.apache.hadoop.ozone.OzoneConsts; + +/** + * This class is used to track Volume Info stats for each HDDS Volume. + */ +@Metrics(about = "Ozone Volume Information Metrics", + context = OzoneConsts.OZONE) +public class VolumeInfoMetrics { + + private String metricsSourceName = VolumeInfoMetrics.class.getSimpleName(); + private String volumeRootStr; + private HddsVolume volume; + + /** + * @param identifier Typically, path to volume root. e.g. /data/hdds + */ + public VolumeInfoMetrics(String identifier, HddsVolume ref) { + this.metricsSourceName += '-' + identifier; + this.volumeRootStr = identifier; + this.volume = ref; + init(); + } + + public void init() { + MetricsSystem ms = DefaultMetricsSystem.instance(); + ms.register(metricsSourceName, "Volume Info Statistics", this); + } + + public void unregister() { + MetricsSystem ms = DefaultMetricsSystem.instance(); + ms.unregisterSource(metricsSourceName); + } + + @Metric("Metric to return the Storage Type") + public String getStorageType() { + return volume.getStorageType().toString(); + } + + @Metric("Returns the Directory name for the volume") + public String getStorageDirectory() { + return volume.getStorageDir().toString(); + } + + @Metric("Return the DataNode UID for the respective volume") + public String getDatanodeUuid() { + return volume.getDatanodeUuid(); + } + + @Metric("Return the Layout Version for the volume") + public int getLayoutVersion() { + return volume.getLayoutVersion(); + } + + @Metric("Returns the Volume Type") + public String getVolumeType() { + return volume.getType().name(); + } + + public String getMetricsSourceName() { + return metricsSourceName; + } + + /** + * Test conservative avail space. + * |----used----| (avail) |++++++++reserved++++++++| + * |<------- capacity ------->| + * |<------------------- Total capacity -------------->| + * A) avail = capacity - used + * B) capacity = used + avail + * C) Total capacity = used + avail + reserved + */ + + /** + * Return the Storage type for the Volume. + */ + @Metric("Returns the Used space") + public long getUsed() { + return volume.getVolumeInfo().getScmUsed(); + } + + /** + * Return the Total Available capacity of the Volume. + */ + @Metric("Returns the Available space") + public long getAvailable() { + return volume.getVolumeInfo().getAvailable(); + } + + /** + * Return the Total Reserved of the Volume. + */ + @Metric("Fetches the Reserved Space") + public long getReserved() { + return volume.getVolumeInfo().getReservedInBytes(); + } + + /** + * Return the Total capacity of the Volume. + */ + @Metric("Returns the Capacity of the Volume") + public long getCapacity() { + return getUsed() + getAvailable(); + } + + /** + * Return the Total capacity of the Volume. + */ + @Metric("Returns the Total Capacity of the Volume") + public long getTotalCapacity() { + return (getUsed() + getAvailable() + getReserved()); + } + +} \ No newline at end of file