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]