You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ozone.apache.org by ad...@apache.org on 2026/10/03 12:28:47 UTC

(ozone) branch master updated: HDDS-14018. Avoid repeated operations in SCMNodeManager#getNodeStatistics (#11292)

This is an automated email from the ASF dual-hosted git repository.

adoroszlai 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 7f7cb3f5597 HDDS-14018. Avoid repeated operations in SCMNodeManager#getNodeStatistics (#11292)
7f7cb3f5597 is described below

commit 7f7cb3f5597e69e138278a8f35f91817bd1a5b2b
Author: Sarveksha Yeshavantha Raju <79...@users.noreply.github.com>
AuthorDate: Sat Oct 3 17:58:40 2026 +0530

    HDDS-14018. Avoid repeated operations in SCMNodeManager#getNodeStatistics (#11292)
---
 .../hadoop/hdds/scm/node/SCMNodeManager.java       | 185 +++++++++++++--------
 1 file changed, 114 insertions(+), 71 deletions(-)

diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
index 6a891e09b5c..d8884cdc464 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
@@ -1187,7 +1187,7 @@ public Map<String, Map<String, Integer>> getNodeCount() {
       }
       nodes.put(opState.name(), states);
     }
-    for (DatanodeInfo dni : nodeStateManager.getAllNodes()) {
+    for (DatanodeInfo dni : getAllNodes()) {
       NodeStatus status = dni.getNodeStatus();
       nodes.get(status.getOperationalState().name())
           .compute(status.getHealth().name(), (k, v) -> v + 1);
@@ -1222,7 +1222,7 @@ public Map<String, Long> getNodeInfo() {
     boolean fsPresent = false;
     boolean fsMissing = false;
 
-    for (DatanodeInfo node : nodeStateManager.getAllNodes()) {
+    for (DatanodeInfo node : getAllNodes()) {
       String keyPrefix = "";
       NodeStatus status = node.getNodeStatus();
       if (status.isMaintenance()) {
@@ -1280,7 +1280,7 @@ public Map<String, Long> getNodeInfo() {
   @Override
   public Map<String, Map<String, String>> getNodeStatusInfo() {
     Map<String, Map<String, String>> nodes = new HashMap<>();
-    for (DatanodeInfo dni : nodeStateManager.getAllNodes()) {
+    for (DatanodeInfo dni : getAllNodes()) {
       String hostName = dni.getHostName();
       DatanodeDetails.Port httpPort = dni.getPort(HTTP);
       DatanodeDetails.Port httpsPort = dni.getPort(HTTPS);
@@ -1374,66 +1374,96 @@ public static String[] calculateStoragePercentage(
     String usedPercentage = "N/A";
     String nonUsedPercentage = "N/A";
     if (storageReports != null && !storageReports.isEmpty()) {
-      long capacity = 0;
-      long scmUsed = 0;
-      long remaining = 0;
+      StorageReportTotals totals = sumStorageReports(storageReports);
+      long scmNonUsed = totals.capacity - totals.scmUsed - totals.remaining;
+      usedPercentage = formatStoragePercentage(
+          ((double) totals.scmUsed / totals.capacity) * 100);
+      nonUsedPercentage = formatStoragePercentage(
+          ((double) scmNonUsed / totals.capacity) * 100);
+    }
+
+    storagePercentage[0] = usedPercentage;
+    storagePercentage[1] = nonUsedPercentage;
+    return storagePercentage;
+  }
+
+  private static StorageReportTotals sumStorageReports(List<StorageReportProto> storageReports) {
+    long capacity = 0;
+    long scmUsed = 0;
+    long remaining = 0;
+    if (storageReports != null) {
       for (StorageReportProto storageReport : storageReports) {
         capacity += storageReport.getCapacity();
         scmUsed += storageReport.getScmUsed();
         remaining += storageReport.getRemaining();
       }
-      long scmNonUsed = capacity - scmUsed - remaining;
-
-      DecimalFormat decimalFormat = TWO_DECIMAL_FORMAT.get();
-
-      double usedPerc = ((double) scmUsed / capacity) * 100;
-      usedPerc = usedPerc > 100.0 ? 100.0 : usedPerc;
-      double nonUsedPerc = ((double) scmNonUsed / capacity) * 100;
-      nonUsedPerc = nonUsedPerc > 100.0 ? 100.0 : nonUsedPerc;
-      usedPercentage = decimalFormat.format(usedPerc);
-      nonUsedPercentage = decimalFormat.format(nonUsedPerc);
     }
+    return new StorageReportTotals(capacity, scmUsed, remaining);
+  }
 
-    storagePercentage[0] = usedPercentage;
-    storagePercentage[1] = nonUsedPercentage;
-    return storagePercentage;
+  private static String formatStoragePercentage(double percentage) {
+    double capped = percentage > 100.0 ? 100.0 : percentage;
+    return TWO_DECIMAL_FORMAT.get().format(capped);
   }
 
   @Override
   public Map<String, String> getNodeStatistics() {
     Map<String, String> nodeStatistics = new HashMap<>();
-    // Statistics node usaged
-    nodeUsageStatistics(nodeStatistics);
+    List<DatanodeInfo> allNodes = getAllNodes();
+    NodeStorageAggregation storageAggregation = aggregateNodeStorage(allNodes);
+    // Statistics node usage
+    nodeUsageStatistics(nodeStatistics, storageAggregation);
     // Statistics node states
-    nodeStateStatistics(nodeStatistics);
+    nodeStateStatistics(nodeStatistics, allNodes);
     // Statistics node space
-    nodeSpaceStatistics(nodeStatistics);
+    nodeSpaceStatistics(nodeStatistics, storageAggregation);
     // Statistics node non-writable
-    nodeNonWritableStatistics(nodeStatistics);
+    nodeNonWritableStatistics(nodeStatistics, allNodes);
     // todo: Statistics of other instances
     return nodeStatistics;
   }
 
-  private void nodeUsageStatistics(Map<String, String> nodeStatics) {
-    if (nodeStateManager.getAllNodes().isEmpty()) {
-      return;
+  private NodeStorageAggregation aggregateNodeStorage(List<DatanodeInfo> allNodes) {
+    if (allNodes.isEmpty()) {
+      return null;
     }
-    float[] usages = new float[nodeStateManager.getAllNodes().size()];
-    float totalOzoneUsed = 0;
-    int i = 0;
-    for (DatanodeInfo dni : nodeStateManager.getAllNodes()) {
-      String[] storagePercentage = calculateStoragePercentage(
-              dni.getStorageReports());
-      if (storagePercentage[0].equals("N/A")) {
-        usages[i++] = 0;
+    long capacityByte = 0;
+    long scmUsedByte = 0;
+    long remainingByte = 0;
+    long totalPending = 0;
+    float[] usages = new float[allNodes.size()];
+    int usageIndex = 0;
+    for (DatanodeInfo dni : allNodes) {
+      totalPending += dni.getPendingContainerAllocations().getCount();
+      List<StorageReportProto> storageReports = dni.getStorageReports();
+      if (storageReports != null && !storageReports.isEmpty()) {
+        StorageReportTotals nodeTotals = sumStorageReports(storageReports);
+        capacityByte += nodeTotals.capacity;
+        scmUsedByte += nodeTotals.scmUsed;
+        remainingByte += nodeTotals.remaining;
+        if (nodeTotals.capacity <= 0) {
+          usages[usageIndex++] = 0;
+        } else {
+          usages[usageIndex++] = Float.parseFloat(formatStoragePercentage(
+              ((double) nodeTotals.scmUsed / nodeTotals.capacity) * 100));
+        }
       } else {
-        float storagePerc = Float.parseFloat(storagePercentage[0]);
-        usages[i++] = storagePerc;
-        totalOzoneUsed = totalOzoneUsed + storagePerc;
+        usages[usageIndex++] = 0;
       }
     }
+    return new NodeStorageAggregation(capacityByte, scmUsedByte, remainingByte, totalPending, usages);
+  }
 
-    totalOzoneUsed /= nodeStateManager.getAllNodes().size();
+  private void nodeUsageStatistics(Map<String, String> nodeStatics, NodeStorageAggregation storageAggregation) {
+    if (storageAggregation == null) {
+      return;
+    }
+    float[] usages = storageAggregation.usages.clone();
+    float totalOzoneUsed = 0;
+    for (float usage : usages) {
+      totalOzoneUsed += usage;
+    }
+    totalOzoneUsed /= usages.length;
     Arrays.sort(usages);
     float median = usages[usages.length / 2];
     nodeStatics.put(UsageStatics.MEDIAN.getLabel(), String.valueOf(median));
@@ -1443,19 +1473,39 @@ private void nodeUsageStatistics(Map<String, String> nodeStatics) {
     nodeStatics.put(UsageStatics.MIN.getLabel(), String.valueOf(min));
 
     float dev = 0;
-    for (i = 0; i < usages.length; i++) {
-      dev += (usages[i] - totalOzoneUsed) * (usages[i] - totalOzoneUsed);
+    for (float usage : usages) {
+      dev += (usage - totalOzoneUsed) * (usage - totalOzoneUsed);
     }
     dev = (float) Math.sqrt(dev / usages.length);
     nodeStatics.put(UsageStatics.STDEV.getLabel(), TWO_DECIMAL_FORMAT.get().format(dev));
   }
 
-  private void nodeStateStatistics(Map<String, String> nodeStatics) {
-    int healthyNodeCount = nodeStateManager.getHealthyNodeCount();
-    int deadNodeCount = nodeStateManager.getDeadNodeCount();
-    int decommissioningNodeCount = nodeStateManager.getDecommissioningNodeCount();
-    int enteringMaintenanceNodeCount = nodeStateManager.getEnteringMaintenanceNodeCount();
-    int volumeFailuresNodeCount = nodeStateManager.getVolumeFailuresNodeCount();
+  private void nodeStateStatistics(Map<String, String> nodeStatics, List<DatanodeInfo> allNodes) {
+    int healthyNodeCount = 0;
+    int deadNodeCount = 0;
+    int decommissioningNodeCount = 0;
+    int enteringMaintenanceNodeCount = 0;
+    int volumeFailuresNodeCount = 0;
+
+    for (DatanodeInfo dni : allNodes) {
+      NodeStatus status = dni.getNodeStatus();
+      if (status.getHealth() == HEALTHY) {
+        healthyNodeCount++;
+      }
+      if (status.isDead()) {
+        deadNodeCount++;
+      }
+      if (status.isDecommissioning()) {
+        decommissioningNodeCount++;
+      }
+      if (status.isEnteringMaintenance()) {
+        enteringMaintenanceNodeCount++;
+      }
+      if (dni.getFailedVolumeCount() > 0) {
+        volumeFailuresNodeCount++;
+      }
+    }
+
     nodeStatics.put(StateStatistics.HEALTHY.getLabel(), String.valueOf(healthyNodeCount));
     nodeStatics.put(StateStatistics.DEAD.getLabel(), String.valueOf(deadNodeCount));
     nodeStatics.put(StateStatistics.DECOMMISSIONING.getLabel(), String.valueOf(decommissioningNodeCount));
@@ -1463,34 +1513,20 @@ private void nodeStateStatistics(Map<String, String> nodeStatics) {
     nodeStatics.put(StateStatistics.VOLUME_FAILURES.getLabel(), String.valueOf(volumeFailuresNodeCount));
   }
 
-  private void nodeSpaceStatistics(Map<String, String> nodeStatics) {
-    if (nodeStateManager.getAllNodes().isEmpty()) {
+  private void nodeSpaceStatistics(Map<String, String> nodeStatics, NodeStorageAggregation storageAggregation) {
+    if (storageAggregation == null) {
       return;
     }
-    long capacityByte = 0;
-    long scmUsedByte = 0;
-    long remainingByte = 0;
-    long totalPending = 0;
-    for (DatanodeInfo dni : nodeStateManager.getAllNodes()) {
-      totalPending += dni.getPendingContainerAllocations().getCount();
-      List<StorageReportProto> storageReports = dni.getStorageReports();
-      if (storageReports != null && !storageReports.isEmpty()) {
-        for (StorageReportProto storageReport : storageReports) {
-          capacityByte += storageReport.getCapacity();
-          scmUsedByte += storageReport.getScmUsed();
-          remainingByte += storageReport.getRemaining();
-        }
-      }
-    }
-    metrics.setTotalPendingContainerSlots(totalPending);
+    metrics.setTotalPendingContainerSlots(storageAggregation.totalPending);
 
-    long nonScmUsedByte = capacityByte - scmUsedByte - remainingByte;
+    long nonScmUsedByte = storageAggregation.capacityByte - storageAggregation.scmUsedByte
+        - storageAggregation.remainingByte;
     if (nonScmUsedByte < 0) {
       nonScmUsedByte = 0;
     }
-    String capacity = convertUnit(capacityByte);
-    String scmUsed = convertUnit(scmUsedByte);
-    String remaining = convertUnit(remainingByte);
+    String capacity = convertUnit(storageAggregation.capacityByte);
+    String scmUsed = convertUnit(storageAggregation.scmUsedByte);
+    String remaining = convertUnit(storageAggregation.remainingByte);
     String nonScmUsed = convertUnit(nonScmUsedByte);
     nodeStatics.put(SpaceStatistics.CAPACITY.getLabel(), capacity);
     nodeStatics.put(SpaceStatistics.SCM_USED.getLabel(), scmUsed);
@@ -1498,8 +1534,8 @@ private void nodeSpaceStatistics(Map<String, String> nodeStatics) {
     nodeStatics.put(SpaceStatistics.NON_SCM_USED.getLabel(), nonScmUsed);
   }
 
-  private void nodeNonWritableStatistics(Map<String, String> nodeStatics) {
-    int nonWritableNodesCount = (int) getAllNodes().parallelStream()
+  private void nodeNonWritableStatistics(Map<String, String> nodeStatics, List<DatanodeInfo> allNodes) {
+    int nonWritableNodesCount = (int) allNodes.parallelStream()
         .filter(nonWritableNodeFilter)
         .count();
 
@@ -1566,6 +1602,13 @@ private boolean hasEnoughCommittedVolumeSpace(DatanodeInfo dnInfo) {
     }
   }
 
+  private record StorageReportTotals(long capacity, long scmUsed, long remaining) {
+  }
+
+  private record NodeStorageAggregation(long capacityByte, long scmUsedByte, long remainingByte, 
+      long totalPending, float[] usages) {
+  }
+
   /**
    * Based on the current time and the last heartbeat, calculate the time difference
    * and get a string of the relative value. E.g. "2s ago", "1m 2s ago", etc.


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ozone.apache.org
For additional commands, e-mail: commits-help@ozone.apache.org