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

ritesh 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 e05e7aeadf HDDS-9934. Display 'Last Heartbeat' in SCM UI in the Node 
Status section (#5803)
e05e7aeadf is described below

commit e05e7aeadfab298dbdc4bc723e1a0e7d02251780
Author: Christos Bisias <[email protected]>
AuthorDate: Mon Dec 18 19:13:20 2023 +0200

    HDDS-9934. Display 'Last Heartbeat' in SCM UI in the Node Status section 
(#5803)
---
 .../src/main/resources/webapps/static/ozone.css    |  2 +-
 .../hadoop/hdds/scm/node/SCMNodeManager.java       | 47 ++++++++++++++++++++++
 .../main/resources/webapps/scm/scm-overview.html   |  9 +++--
 .../src/main/resources/webapps/scm/scm.js          |  1 +
 .../hadoop/hdds/scm/node/TestSCMNodeManager.java   | 33 +++++++++++++++
 5 files changed, 88 insertions(+), 4 deletions(-)

diff --git a/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.css 
b/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.css
index 373626e026..e08e9c5206 100644
--- a/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.css
+++ b/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.css
@@ -80,7 +80,7 @@ body {
      display: block;
      font-family: 'Glyphicons Halflings';
  }
-.nodeStausInfo {
+.nodeStatusInfo {
     position: relative;
  }
 .wrap-table{
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 972c061d5d..b34f5819f6 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
@@ -83,6 +83,7 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
@@ -139,6 +140,7 @@ public class SCMNodeManager implements NodeManager {
   private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
   private final String opeState = "OPSTATE";
   private final String comState = "COMSTATE";
+  private final String lastHeartbeat = "LASTHEARTBEAT";
   /**
    * Constructs SCM machine Manager.
    */
@@ -1080,13 +1082,16 @@ public class SCMNodeManager implements NodeManager {
       DatanodeDetails.Port httpsPort = dni.getPort(HTTPS);
       String opstate = "";
       String healthState = "";
+      String heartbeatTimeDiff = "";
       if (dni.getNodeStatus() != null) {
         opstate = dni.getNodeStatus().getOperationalState().toString();
         healthState = dni.getNodeStatus().getHealth().toString();
+        heartbeatTimeDiff = 
getLastHeartbeatTimeDiff(dni.getLastHeartbeatTime());
       }
       Map<String, String> map = new HashMap<>();
       map.put(opeState, opstate);
       map.put(comState, healthState);
+      map.put(lastHeartbeat, heartbeatTimeDiff);
       if (httpPort != null) {
         map.put(httpPort.getName().toString(), httpPort.getValue().toString());
       }
@@ -1099,6 +1104,48 @@ public class SCMNodeManager implements NodeManager {
     return nodes;
   }
 
+  /**
+   * 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.
+   *
+   * @return string with the relative value of the time diff.
+   */
+  public String getLastHeartbeatTimeDiff(long lastHeartbeatTime) {
+    long currentTime = Time.monotonicNow();
+    long timeDiff = currentTime - lastHeartbeatTime;
+
+    // Time is in ms. Calculate total time in seconds.
+    long seconds = TimeUnit.MILLISECONDS.toSeconds(timeDiff);
+    // Calculate days, convert the number back to seconds and subtract it from 
seconds.
+    long days = TimeUnit.SECONDS.toDays(seconds);
+    seconds -= TimeUnit.DAYS.toSeconds(days);
+    // Calculate hours, convert the number back to seconds and subtract it 
from seconds.
+    long hours = TimeUnit.SECONDS.toHours(seconds);
+    seconds -= TimeUnit.HOURS.toSeconds(hours);
+    // Calculate minutes, convert the number back to seconds and subtract it 
from seconds.
+    long minutes = TimeUnit.SECONDS.toMinutes(seconds);
+    seconds -= TimeUnit.MINUTES.toSeconds(minutes);
+
+    StringBuilder stringBuilder = new StringBuilder();
+    if (days > 0) {
+      stringBuilder.append(days).append("d ");
+    }
+    if (hours > 0) {
+      stringBuilder.append(hours).append("h ");
+    }
+    if (minutes > 0) {
+      stringBuilder.append(minutes).append("m ");
+    }
+    if (seconds > 0) {
+      stringBuilder.append(seconds).append("s ");
+    }
+    String str = stringBuilder.length() == 0 ? "Just now" : "ago";
+
+    stringBuilder.append(str);
+
+    return stringBuilder.toString();
+  }
+
   private enum UsageMetrics {
     DiskCapacity,
     DiskUsed,
diff --git 
a/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm-overview.html 
b/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm-overview.html
index 5929610def..214a2ad786 100644
--- a/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm-overview.html
+++ b/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm-overview.html
@@ -46,12 +46,14 @@
 <table class="table table-bordered table-striped col-md-6">
     <thead>
         <tr>
-            <th ng-click = "columnSort('hostname')" 
class="nodeStausInfo"><span ng-class = "{'sorting' : (columnName != 
'hostname'), 'sortasc' : (columnName == 'hostname' && !reverse),
+            <th ng-click = "columnSort('hostname')" 
class="nodeStatusInfo"><span ng-class = "{'sorting' : (columnName != 
'hostname'), 'sortasc' : (columnName == 'hostname' && !reverse),
                                         'sortdesc':(columnName == 'hostname' 
&& !reverse)}">HostName</span></th>
-            <th ng-click = "columnSort('opstate')" class="nodeStausInfo" 
><span ng-class="{'sorting' : (columnName != 'opstate'), 'sortasc' : 
(columnName == 'opstate' && !reverse),
+            <th ng-click = "columnSort('opstate')" class="nodeStatusInfo" 
><span ng-class="{'sorting' : (columnName != 'opstate'), 'sortasc' : 
(columnName == 'opstate' && !reverse),
                                         'sortdesc':(columnName == 'opstate' && 
!reverse)}">Operational State</span></th>
-            <th ng-click = "columnSort('comstate')" class="nodeStausInfo">  
<span ng-class="{'sorting' : (columnName != 'comstate'), 'sortasc' : 
(columnName == 'comstate' && !reverse),
+            <th ng-click = "columnSort('comstate')" class="nodeStatusInfo">  
<span ng-class="{'sorting' : (columnName != 'comstate'), 'sortasc' : 
(columnName == 'comstate' && !reverse),
                                         'sortdesc':(columnName == 'comstate' 
&& !reverse)}">Commisioned State</span> </th>
+            <th ng-click = "columnSort('lastheartbeat')" 
class="nodeStatusInfo">  <span ng-class="{'sorting' : (columnName != 
'lastheartbeat'), 'sortasc' : (columnName == 'heartbeat' && !reverse),
+                                        'sortdesc':(columnName == 
'lastheartbeat' && !reverse)}">Last Heartbeat</span> </th>
         </tr>
     </thead>
     <tbody>
@@ -66,6 +68,7 @@
             </td>
             <td>{{typestat.opstate}}</td>
             <td>{{typestat.comstate}}</td>
+            <td>{{typestat.lastheartbeat}}</td>
        </tr>
     </tbody>
 </table>
diff --git a/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js 
b/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js
index aee56ad266..3802a8f744 100644
--- a/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js
+++ b/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js
@@ -69,6 +69,7 @@
                                     hostname: key,
                                     opstate: value && value.find((element) => 
element.key === "OPSTATE").value,
                                     comstate: value && value.find((element) => 
element.key === "COMSTATE").value,
+                                    lastheartbeat: value && 
value.find((element) => element.key === "LASTHEARTBEAT").value,
                                     port: portSpec.port,
                                     protocol: portSpec.proto
                                 }
diff --git 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestSCMNodeManager.java
 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestSCMNodeManager.java
index a3decb0efb..333830a7d7 100644
--- 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestSCMNodeManager.java
+++ 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestSCMNodeManager.java
@@ -77,6 +77,7 @@ import org.apache.hadoop.ozone.protocol.commands.SCMCommand;
 import org.apache.hadoop.ozone.upgrade.LayoutVersionManager;
 import 
org.apache.hadoop.ozone.protocol.commands.SetNodeOperationalStateCommand;
 import 
org.apache.hadoop.security.authentication.client.AuthenticationException;
+import org.apache.hadoop.util.Time;
 import org.apache.ozone.test.GenericTestUtils;
 import org.apache.hadoop.test.PathUtils;
 import org.junit.jupiter.api.AfterEach;
@@ -238,6 +239,38 @@ public class TestSCMNodeManager {
     }
   }
 
+  @Test
+  public void testGetLastHeartbeatTimeDiff() throws Exception {
+    try (SCMNodeManager nodeManager = createNodeManager(getConf())) {
+      String timeNow = 
nodeManager.getLastHeartbeatTimeDiff(Time.monotonicNow());
+      assertEquals("Just now", timeNow);
+
+      String time1s = nodeManager.getLastHeartbeatTimeDiff(Time.monotonicNow() 
- 10000);
+      assertEquals("10s ago", time1s);
+
+      String time1m = nodeManager.getLastHeartbeatTimeDiff(Time.monotonicNow() 
- 60000);
+      assertEquals("1m ago", time1m);
+
+      String time1m10s = 
nodeManager.getLastHeartbeatTimeDiff(Time.monotonicNow() - 70000);
+      assertEquals("1m 10s ago", time1m10s);
+
+      // 1h 1m 10s
+      // 10000ms = 10s
+      // 60000ms = 1m
+      // 60000ms * 60 = 3600000ms = 1h
+      String time1h1m10s = 
nodeManager.getLastHeartbeatTimeDiff(Time.monotonicNow() - 3670000);
+      assertEquals("1h 1m 10s ago", time1h1m10s);
+
+      // 1d 1h 1m 10s
+      // 10000ms = 10s
+      // 60000ms = 1m
+      // 60000ms * 60 = 3600000ms = 1h
+      // 3600000ms * 24 = 86400000ms = 1d
+      String time1d1h1m10s = 
nodeManager.getLastHeartbeatTimeDiff(Time.monotonicNow() - 90070000);
+      assertEquals("1d 1h 1m 10s ago", time1d1h1m10s);
+    }
+  }
+
   /**
    * Tests that node manager handles layout version changes from heartbeats
    * correctly.


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to