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

jojochuang 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 8261cb9c0fd HDDS-15095. Deletion Metrics Page for Ozone Manager Web 
UI. (#10110)
8261cb9c0fd is described below

commit 8261cb9c0fd6b78a279588126c70fb8a61652505
Author: Sadanand Shenoy <[email protected]>
AuthorDate: Wed May 13 01:19:45 2026 +0530

    HDDS-15095. Deletion Metrics Page for Ozone Manager Web UI. (#10110)
---
 .../common/src/main/resources/ozone-default.xml    |  34 ++--
 .../src/main/resources/webapps/static/ozone.js     |   2 +
 .../resources/webapps/static/templates/menu.html   |   3 +
 .../hadoop/ozone/om/DeletingServiceMetrics.java    |  37 ++++
 .../ozone/om/service/DirectoryDeletingService.java |  41 +++++
 .../main/resources/webapps/ozoneManager/index.html |   3 +-
 .../webapps/ozoneManager/om-deletion.html          | 186 +++++++++++++++++++++
 .../webapps/ozoneManager/om-overview.html          |  59 -------
 .../resources/webapps/ozoneManager/ozoneManager.js |  92 ++++++++--
 9 files changed, 364 insertions(+), 93 deletions(-)

diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml 
b/hadoop-hdds/common/src/main/resources/ozone-default.xml
index f554b440602..d0a96e93228 100644
--- a/hadoop-hdds/common/src/main/resources/ozone-default.xml
+++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml
@@ -431,7 +431,7 @@
   <property>
     <name>ozone.block.deleting.service.interval</name>
     <value>1m</value>
-    <tag>OZONE, PERFORMANCE, SCM</tag>
+    <tag>OZONE, PERFORMANCE, SCM, DELETION</tag>
     <description>Time interval of the block deleting service.
       The block deleting service runs on each datanode periodically and
       deletes blocks queued for deletion. Unit could be defined with
@@ -441,7 +441,7 @@
   <property>
     <name>ozone.block.deleting.service.timeout</name>
     <value>300000ms</value>
-    <tag>OZONE, PERFORMANCE, SCM</tag>
+    <tag>OZONE, PERFORMANCE, SCM, DELETION</tag>
     <description>A timeout value of block deletion service. If this is set
       greater than 0,
       the service will stop waiting for the block deleting completion after 
this
@@ -454,7 +454,7 @@
   <property>
     <name>ozone.block.deleting.service.workers</name>
     <value>10</value>
-    <tag>OZONE, PERFORMANCE, SCM</tag>
+    <tag>OZONE, PERFORMANCE, SCM, DELETION</tag>
     <description>Number of workers executed of block deletion service. This
       configuration should be set to greater than 0.
     </description>
@@ -496,7 +496,7 @@
   <property>
     <name>ozone.key.deleting.limit.per.task</name>
     <value>50000</value>
-    <tag>OM, PERFORMANCE</tag>
+    <tag>OM, PERFORMANCE, DELETION</tag>
     <description>
       A maximum number of keys to be scanned by key deleting service
       per time interval in OM. Those keys are sent to delete metadata and
@@ -507,7 +507,7 @@
   <property>
     <name>ozone.snapshot.key.deleting.limit.per.task</name>
     <value>20000</value>
-    <tag>OM, PERFORMANCE</tag>
+    <tag>OM, PERFORMANCE, DELETION</tag>
     <description>
       The maximum number of deleted keys to be scanned by Snapshot
       Deleting Service per snapshot run.
@@ -706,7 +706,7 @@
   <property>
     <name>ozone.path.deleting.limit.per.task</name>
     <value>20000</value>
-    <tag>OZONE, PERFORMANCE, OM</tag>
+    <tag>OZONE, PERFORMANCE, OM, DELETION</tag>
     <description>A maximum number of paths(dirs/files) to be deleted by
       directory deleting service per time interval.
     </description>
@@ -793,7 +793,7 @@
   <property>
     <name>ozone.scm.block.deletion.per.dn.distribution.factor</name>
     <value>8</value>
-    <tag>OZONE, SCM</tag>
+    <tag>OZONE, SCM, DELETION</tag>
     <description>
       Factor with which number of delete blocks sent to each datanode in every 
interval.
       If total number of DNs are 100 and 
hdds.scm.block.deletion.per-interval.max is 500000
@@ -910,7 +910,7 @@
   <property>
     <name>ozone.scm.keyvalue.container.deletion-choosing.policy</name>
     
<value>org.apache.hadoop.ozone.container.common.impl.TopNOrderedContainerDeletionChoosingPolicy</value>
-    <tag>OZONE, MANAGEMENT</tag>
+    <tag>OZONE, MANAGEMENT, DELETION</tag>
     <description>
       The policy used for choosing desired keyvalue containers for block 
deletion.
       Datanode selects some containers to process block deletion
@@ -3915,7 +3915,7 @@
   <property>
     <name>ozone.directory.deleting.service.interval</name>
     <value>1m</value>
-    <tag>OZONE, PERFORMANCE, OM</tag>
+    <tag>OZONE, PERFORMANCE, OM, DELETION</tag>
     <description>Time interval of the directory deleting service. It runs on OM
       periodically and cleanup orphan directory and its sub-tree. For every
       orphan directory it deletes the sub-path tree structure(dirs/files). It
@@ -3926,7 +3926,7 @@
   <property>
     <name>ozone.snapshot.filtering.limit.per.task</name>
     <value>2</value>
-    <tag>OZONE, PERFORMANCE, OM</tag>
+    <tag>OZONE, PERFORMANCE, OM, DELETION</tag>
     <description>A maximum number of snapshots to be filtered by
       sst filtering service per time interval.
     </description>
@@ -3934,7 +3934,7 @@
   <property>
     <name>ozone.snapshot.deleting.limit.per.task</name>
     <value>10</value>
-    <tag>OZONE, PERFORMANCE, OM</tag>
+    <tag>OZONE, PERFORMANCE, OM, DELETION</tag>
     <description>The maximum number of snapshots that would be reclaimed by
       Snapshot Deleting Service per run.
     </description>
@@ -3950,7 +3950,7 @@
   <property>
     <name>ozone.snapshot.filtering.service.interval</name>
     <value>1m</value>
-    <tag>OZONE, PERFORMANCE, OM</tag>
+    <tag>OZONE, PERFORMANCE, OM, DELETION</tag>
     <description>Time interval of the SST File filtering service from Snapshot.
     </description>
   </property>
@@ -3973,14 +3973,14 @@
   <property>
     <name>ozone.sst.filtering.service.timeout</name>
     <value>300000ms</value>
-    <tag>OZONE, PERFORMANCE,OM</tag>
+    <tag>OZONE, PERFORMANCE, OM, DELETION</tag>
     <description>A timeout value of sst filtering service.
     </description>
   </property>
   <property>
     <name>ozone.snapshot.defrag.service.timeout</name>
     <value>300s</value>
-    <tag>OZONE, PERFORMANCE,OM</tag>
+    <tag>OZONE, PERFORMANCE, OM</tag>
     <description>Timeout value of a run of snapshot defragmentation service.
     </description>
   </property>
@@ -4008,7 +4008,7 @@
   <property>
     <name>ozone.snapshot.deleting.service.timeout</name>
     <value>300s</value>
-    <tag>OZONE, PERFORMANCE, OM</tag>
+    <tag>OZONE, PERFORMANCE, OM, DELETION</tag>
     <description>
       Timeout value for SnapshotDeletingService.
     </description>
@@ -4017,7 +4017,7 @@
   <property>
     <name>ozone.snapshot.deleting.service.interval</name>
     <value>30s</value>
-    <tag>OZONE, PERFORMANCE, OM</tag>
+    <tag>OZONE, PERFORMANCE, OM, DELETION</tag>
     <description>
       The time interval between successive SnapshotDeletingService
       thread run.
@@ -4046,7 +4046,7 @@
   <property>
     <name>ozone.snapshot.deep.cleaning.enabled</name>
     <value>false</value>
-    <tag>OZONE, PERFORMANCE, OM</tag>
+    <tag>OZONE, PERFORMANCE, OM, DELETION</tag>
     <description>
       Flag to enable/disable snapshot deep cleaning.
     </description>
diff --git a/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.js 
b/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.js
index 2835c3633e5..356b0e3f63f 100644
--- a/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.js
+++ b/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.js
@@ -252,6 +252,8 @@
   angular.module('ozone').component('navmenu', {
     bindings: {
       metrics: '<',
+      /** Optional list of {label, href} for extra top-level nav items (e.g. 
OM deletion dashboard). */
+      extraNavLinks: '<',
       iostatus: '<',
       ioLinkHref: '@',
       scanner: '<',
diff --git 
a/hadoop-hdds/framework/src/main/resources/webapps/static/templates/menu.html 
b/hadoop-hdds/framework/src/main/resources/webapps/static/templates/menu.html
index b488a6982e7..889d061aebc 100644
--- 
a/hadoop-hdds/framework/src/main/resources/webapps/static/templates/menu.html
+++ 
b/hadoop-hdds/framework/src/main/resources/webapps/static/templates/menu.html
@@ -33,6 +33,9 @@
                         aria-hidden="true"></span></a></li>
             </ul>
         </li>
+        <li ng-repeat="link in ($ctrl.extraNavLinks || []) track by ($index + 
'-' + link.href)">
+            <a ng-href="{{link.href}}">{{link.label}}</a>
+        </li>
         <li><a href="#!/config">Configuration</a></li>
         <li><a href="#!/ratis_events">Ratis event timeline</a></li>
         <li ng-show="$ctrl.docs"><a href="/docs">Documentation</a></li>
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/DeletingServiceMetrics.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/DeletingServiceMetrics.java
index ec4a110a4f9..56ccdac79b6 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/DeletingServiceMetrics.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/DeletingServiceMetrics.java
@@ -89,6 +89,10 @@ public final class DeletingServiceMetrics {
   private MutableGaugeLong kdsLastRunTimestamp;
   @Metric("Key Deleting Service current run timestamp in ms")
   private MutableGaugeLong kdsCurRunTimestamp;
+  @Metric("Directory Deleting Service last run start timestamp in ms")
+  private MutableGaugeLong ddsLastRunTimestamp;
+  @Metric("Directory Deleting Service current run start timestamp in ms")
+  private MutableGaugeLong ddsCurRunTimestamp;
 
   /*
    * Deletion service last run metrics.
@@ -110,6 +114,19 @@ public final class DeletingServiceMetrics {
   @Metric("Snapshot: No. of not reclaimable keys the last run")
   private MutableGaugeLong snapKeysNotReclaimableLast;
 
+  @Metric("AOS: deleted directories sent for purge in the last 
DirectoryDeletingService run")
+  private MutableGaugeLong ddsAosDirsSentForPurgeLast;
+  @Metric("AOS: sub-directories in the last DirectoryDeletingService run 
(mark/purge as applicable)")
+  private MutableGaugeLong ddsAosSubDirsLast;
+  @Metric("AOS: sub-files in the last DirectoryDeletingService run")
+  private MutableGaugeLong ddsAosSubFilesLast;
+  @Metric("Snapshot: deleted directories sent for purge in the last 
DirectoryDeletingService run")
+  private MutableGaugeLong ddsSnapDirsSentForPurgeLast;
+  @Metric("Snapshot: sub-directories in the last DirectoryDeletingService run 
(mark/purge as applicable)")
+  private MutableGaugeLong ddsSnapSubDirsLast;
+  @Metric("Snapshot: sub-files in the last DirectoryDeletingService run")
+  private MutableGaugeLong ddsSnapSubFilesLast;
+
   /**
    * Metric to track the term ID of the last key that was purged from the
    * Active Object Store (AOS). This term ID represents the state of the
@@ -221,6 +238,26 @@ public void setKdsCurRunTimestamp(long timestamp) {
     this.kdsCurRunTimestamp.set(timestamp);
   }
 
+  public void setDdsLastRunTimestamp(long timestamp) {
+    this.ddsLastRunTimestamp.set(timestamp);
+  }
+
+  public void setDdsCurRunTimestamp(long timestamp) {
+    this.ddsCurRunTimestamp.set(timestamp);
+  }
+
+  public void updateAosDdsLastRunMetrics(long dirsSentForPurge, long subDirs, 
long subFiles) {
+    this.ddsAosDirsSentForPurgeLast.set(dirsSentForPurge);
+    this.ddsAosSubDirsLast.set(subDirs);
+    this.ddsAosSubFilesLast.set(subFiles);
+  }
+
+  public void updateSnapDdsLastRunMetrics(long dirsSentForPurge, long subDirs, 
long subFiles) {
+    this.ddsSnapDirsSentForPurgeLast.set(dirsSentForPurge);
+    this.ddsSnapSubDirsLast.set(subDirs);
+    this.ddsSnapSubFilesLast.set(subFiles);
+  }
+
   private void resetMetrics() {
     this.keysReclaimedInInterval.set(0);
     this.reclaimedSizeInInterval.set(0);
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/DirectoryDeletingService.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/DirectoryDeletingService.java
index 0ecf64c5083..cd0b3c90e87 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/DirectoryDeletingService.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/DirectoryDeletingService.java
@@ -164,6 +164,13 @@ public class DirectoryDeletingService extends 
AbstractKeyDeletingService {
   private final AtomicLong movedDirsCount;
   private final AtomicLong movedFilesCount;
   private final int pathLimitPerTask;
+  private long ddsRunStartMs;
+  private final AtomicLong ddsRoundAosDirDel = new AtomicLong(0);
+  private final AtomicLong ddsRoundAosSubDir = new AtomicLong(0);
+  private final AtomicLong ddsRoundAosSubFile = new AtomicLong(0);
+  private final AtomicLong ddsRoundSnapDirDel = new AtomicLong(0);
+  private final AtomicLong ddsRoundSnapSubDir = new AtomicLong(0);
+  private final AtomicLong ddsRoundSnapSubFile = new AtomicLong(0);
 
   public DirectoryDeletingService(long interval, TimeUnit unit,
       long serviceTimeout, OzoneManager ozoneManager,
@@ -214,6 +221,9 @@ private synchronized void 
updateAndRestart(OzoneConfiguration conf) {
 
   @Override
   public DeletingServiceTaskQueue getTasks() {
+    resetDdsRoundStats();
+    ddsRunStartMs = System.currentTimeMillis();
+    getMetrics().setDdsCurRunTimestamp(ddsRunStartMs);
     DeletingServiceTaskQueue queue = new DeletingServiceTaskQueue();
     queue.add(new DirDeletingTask(null));
     if (deepCleanSnapshots) {
@@ -232,6 +242,36 @@ public DeletingServiceTaskQueue getTasks() {
     return queue;
   }
 
+  private void resetDdsRoundStats() {
+    ddsRoundAosDirDel.set(0);
+    ddsRoundAosSubDir.set(0);
+    ddsRoundAosSubFile.set(0);
+    ddsRoundSnapDirDel.set(0);
+    ddsRoundSnapSubDir.set(0);
+    ddsRoundSnapSubFile.set(0);
+  }
+
+  private void addDdsRoundContribution(String snapTableKey, long dirDel, long 
subDirs, long subFiles) {
+    if (snapTableKey == null) {
+      ddsRoundAosDirDel.addAndGet(dirDel);
+      ddsRoundAosSubDir.addAndGet(subDirs);
+      ddsRoundAosSubFile.addAndGet(subFiles);
+    } else {
+      ddsRoundSnapDirDel.addAndGet(dirDel);
+      ddsRoundSnapSubDir.addAndGet(subDirs);
+      ddsRoundSnapSubFile.addAndGet(subFiles);
+    }
+  }
+
+  @Override
+  protected void execTaskCompletion() {
+    getMetrics().updateAosDdsLastRunMetrics(
+        ddsRoundAosDirDel.get(), ddsRoundAosSubDir.get(), 
ddsRoundAosSubFile.get());
+    getMetrics().updateSnapDdsLastRunMetrics(
+        ddsRoundSnapDirDel.get(), ddsRoundSnapSubDir.get(), 
ddsRoundSnapSubFile.get());
+    getMetrics().setDdsLastRunTimestamp(ddsRunStartMs);
+  }
+
   @Override
   public void shutdown() {
     if (deletionThreadPool != null) {
@@ -335,6 +375,7 @@ void optimizeDirDeletesAndSubmitRequest(
           dirNum, subdirDelNum, subFileNum, (subDirNum - subdirDelNum),
           timeTakenInIteration, rnCnt);
       getMetrics().incrementDirectoryDeletionTotalMetrics(dirNum + 
subdirDelNum, subDirNum, subFileNum);
+      addDdsRoundContribution(snapTableKey, dirNum + subdirDelNum, subDirNum, 
subFileNum);
       
getPerfMetrics().setDirectoryDeletingServiceLatencyMs(timeTakenInIteration);
     }
   }
diff --git 
a/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/index.html 
b/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/index.html
index 153000c2c91..5063b3d64c6 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/index.html
+++ 
b/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/index.html
@@ -34,7 +34,7 @@
 
 </head>
 
-<body ng-app="ozoneManager">
+<body ng-app="ozoneManager" ng-init="omExtraNavLinks = [{label: 'Deletion', 
href: '#!/metrics/deletion'}]">
 
 <header class="navbar navbar-inverse navbar-fixed-top bs-docs-nav">
     <div class="container-fluid">
@@ -49,6 +49,7 @@
             <a class="navbar-brand" href="#">Ozone Manager</a>
         </div>
         <navmenu
+            extra-nav-links="omExtraNavLinks"
                 metrics="{ 'OM metrics' : '#!/metrics/ozoneManager', 'Rpc 
metrics' : '#!/metrics/rpc'}"
                 snapshot="true"
                 snapshot-link-href="#!/snapshots"></navmenu>
diff --git 
a/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/om-deletion.html
 
b/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/om-deletion.html
new file mode 100644
index 00000000000..d8e74ab38f1
--- /dev/null
+++ 
b/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/om-deletion.html
@@ -0,0 +1,186 @@
+<!--
+   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.
+-->
+
+<h1>Deletion services</h1>
+
+<div class="alert alert-info" ng-show="$ctrl.role && ($ctrl.role.Role || 
'').trim() !== 'LEADER'">
+    <p class="m-0">
+        <strong>This node is not the OM leader.</strong>
+        Key and directory deletion services run on the leader only; deletion 
settings and the metrics
+        on this page reflect the process where you are connected, not live 
leader work.
+        Open the <strong>Ozone Manager</strong> web UI on the 
<strong>leader</strong> OM to view
+        current deletion configuration and metrics.
+    </p>
+</div>
+
+<div ng-show="!$ctrl.role || ($ctrl.role.Role || '').trim() === 'LEADER'">
+<h2>Effective configuration (DELETION tag)</h2>
+<p class="text-muted small">Properties tagged <code>DELETION</code> in 
<code>ozone-default.xml</code>, loaded via 
<code>conf?cmd=getPropertyByTag&amp;tags=DELETION</code>.</p>
+<p class="text-muted" ng-show="!$ctrl.deletionConfigs.length">No matching 
deletion-related properties found, or configuration is still loading.</p>
+<table class="table table-bordered table-striped" 
ng-show="$ctrl.deletionConfigs.length">
+    <thead>
+    <tr>
+        <th class="col-md-3">Property</th>
+        <th class="col-md-2">Value</th>
+        <th class="col-md-7">Description</th>
+    </tr>
+    </thead>
+    <tbody>
+    <tr ng-repeat="c in $ctrl.deletionConfigs">
+        <td style="word-break: break-all;">{{c.name}}</td>
+        <td style="word-break: break-all;">{{c.value}}</td>
+        <td>{{c.description}}</td>
+    </tr>
+    </tbody>
+</table>
+
+<h2>Service iteration latency (last run)</h2>
+<p class="text-muted" ng-show="!$ctrl.perf">OMPerformanceMetrics JMX bean not 
available.</p>
+<table class="table table-bordered table-striped" ng-show="$ctrl.perf">
+    <tbody>
+    <tr>
+        <td>KeyDeletingService (ms)</td>
+        <td>{{$ctrl.perf.KeyDeletingServiceLatencyMs != null ? 
$ctrl.perf.KeyDeletingServiceLatencyMs : 'N/A'}}</td>
+    </tr>
+    <tr>
+        <td>DirectoryDeletingService (ms)</td>
+        <td>{{$ctrl.perf.DirectoryDeletingServiceLatencyMs != null ? 
$ctrl.perf.DirectoryDeletingServiceLatencyMs : 'N/A'}}</td>
+    </tr>
+    </tbody>
+</table>
+
+<div ng-show="!$ctrl.del" class="text-muted">DeletingServiceMetrics JMX bean 
not available.</div>
+<div ng-show="$ctrl.del">
+    <h2>Deletion Progress [{{$ctrl.del.MetricsResetTimeStamp ? 'since ' + 
($ctrl.del.MetricsResetTimeStamp * 1000 | date:'yyyy-MM-dd HH:mm:ss') : 
'Initializing'}}]
+        &nbsp;&nbsp;&bull;&nbsp;&nbsp;
+        <b>Size Reclaimed:</b> 
{{$ctrl.formatBytes($ctrl.del.ReclaimedSizeInInterval)}}
+        &nbsp;&nbsp;&bull;&nbsp;&nbsp;
+        <b>Keys Reclaimed:</b> {{$ctrl.del.KeysReclaimedInInterval || 0}}
+    </h2>
+    <h3>KeyDeletingService (last run)</h3>
+    <div class="mt-3">
+        <div class="row mb-2" ng-if="$ctrl.del.KdsCurRunTimestamp">
+            <div class="col-md-3"><b>Current Run Started:</b></div>
+            <div class="col-md-9">{{$ctrl.convertMsToTime($ctrl.Date.now() - 
$ctrl.del.KdsCurRunTimestamp)}} ago</div>
+        </div>
+        <div class="row mb-2" ng-if="$ctrl.del.KdsLastRunTimestamp">
+            <div class="col-md-3"><b>Last Run:</b></div>
+            <div class="col-md-9">{{$ctrl.convertMsToTime($ctrl.Date.now() - 
$ctrl.del.KdsLastRunTimestamp)}} ago</div>
+        </div>
+    </div>
+    <div style="margin-bottom: 2px;"></div>
+    <table class="table table-sm table-bordered mt-2">
+        <thead>
+        <tr>
+            <th>Store</th>
+            <th>Reclaimed Size</th>
+            <th>#Reclaimed Keys</th>
+            <th>#Iterated Keys</th>
+            <th>#NotReclaimable Keys (Referred by Snapshots)</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr>
+            <td>Active Object Store</td>
+            <td>{{$ctrl.formatBytes($ctrl.del.AosReclaimedSizeLast)}}</td>
+            <td>{{$ctrl.del.AosKeysReclaimedLast || 0}}</td>
+            <td>{{$ctrl.del.AosKeysIteratedLast || 0}}</td>
+            <td>{{$ctrl.del.AosKeysNotReclaimableLast || 0}}</td>
+        </tr>
+        <tr>
+            <td>Snapshots</td>
+            <td>{{$ctrl.formatBytes($ctrl.del.SnapReclaimedSizeLast)}}</td>
+            <td>{{$ctrl.del.SnapKeysReclaimedLast || 0}}</td>
+            <td>{{$ctrl.del.SnapKeysIteratedLast || 0}}</td>
+            <td>{{$ctrl.del.SnapKeysNotReclaimableLast || 0}}</td>
+        </tr>
+        </tbody>
+    </table>
+
+    <h3>DirectoryDeletingService (last run)</h3>
+    <div class="mt-3">
+        <div class="row mb-2" ng-if="$ctrl.del.DdsCurRunTimestamp">
+            <div class="col-md-3"><b>Current Run Started:</b></div>
+            <div class="col-md-9">{{$ctrl.convertMsToTime($ctrl.Date.now() - 
$ctrl.del.DdsCurRunTimestamp)}} ago</div>
+        </div>
+        <div class="row mb-2" ng-if="$ctrl.del.DdsLastRunTimestamp">
+            <div class="col-md-3"><b>Last Completed Run Started:</b></div>
+            <div class="col-md-9">{{$ctrl.convertMsToTime($ctrl.Date.now() - 
$ctrl.del.DdsLastRunTimestamp)}} ago</div>
+        </div>
+    </div>
+    <table class="table table-sm table-bordered mt-2">
+        <thead>
+        <tr>
+            <th>Store</th>
+            <th>Dirs sent for purge</th>
+            <th>Sub-dirs</th>
+            <th>Sub-files</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr>
+            <td>Active Object Store</td>
+            <td>{{$ctrl.del.DdsAosDirsSentForPurgeLast || 0}}</td>
+            <td>{{$ctrl.del.DdsAosSubDirsLast || 0}}</td>
+            <td>{{$ctrl.del.DdsAosSubFilesLast || 0}}</td>
+        </tr>
+        <tr>
+            <td>Snapshots</td>
+            <td>{{$ctrl.del.DdsSnapDirsSentForPurgeLast || 0}}</td>
+            <td>{{$ctrl.del.DdsSnapSubDirsLast || 0}}</td>
+            <td>{{$ctrl.del.DdsSnapSubFilesLast || 0}}</td>
+        </tr>
+        </tbody>
+    </table>
+
+    <h3>DirectoryDeletingService (cumulative since OM restart)</h3>
+    <table class="table table-bordered table-striped table-condensed">
+        <tbody>
+        <tr><td>Deleted directories sent for 
purge</td><td>{{$ctrl.del.NumDirsSentForPurge || 0}}</td></tr>
+        <tr><td>Sub-directories sent for 
purge</td><td>{{$ctrl.del.NumSubDirsSentForPurge || 0}}</td></tr>
+        <tr><td>Sub-files sent for 
purge</td><td>{{$ctrl.del.NumSubFilesSentForPurge || 0}}</td></tr>
+        </tbody>
+    </table>
+
+    <h3>Directory purge handling</h3>
+    <table class="table table-bordered table-striped table-condensed">
+        <tbody>
+        <tr><td>Directories purged</td><td>{{$ctrl.del.NumDirsPurged || 
0}}</td></tr>
+        <tr><td>Sub-files moved to 
deletedTable</td><td>{{$ctrl.del.NumSubFilesMovedToDeletedTable || 0}}</td></tr>
+        <tr><td>Sub-directories moved to 
deletedDirTable</td><td>{{$ctrl.del.NumSubDirsMovedToDeletedDirTable || 
0}}</td></tr>
+        </tbody>
+    </table>
+
+    <h3>KeyDeletingService (cumulative since OM restart)</h3>
+    <table class="table table-bordered table-striped table-condensed">
+        <tbody>
+        <tr><td>Keys processed</td><td>{{$ctrl.del.NumKeysProcessed || 
0}}</td></tr>
+        <tr><td>Deleted keys sent for 
purge</td><td>{{$ctrl.del.NumKeysSentForPurge || 0}}</td></tr>
+        <tr><td>Keys purged</td><td>{{$ctrl.del.NumKeysPurged || 0}}</td></tr>
+        <tr><td>Rename entries 
purged</td><td>{{$ctrl.del.NumRenameEntriesPurged || 0}}</td></tr>
+        </tbody>
+    </table>
+
+    <h3>Purge coordination (AOS)</h3>
+    <table class="table table-bordered table-striped table-condensed">
+        <tbody>
+        <tr><td>Last purge term index</td><td>{{$ctrl.del.LastAOSPurgeTermId 
!= null ? $ctrl.del.LastAOSPurgeTermId : 'N/A'}}</td></tr>
+        <tr><td>Last purge transaction 
index</td><td>{{$ctrl.del.LastAOSPurgeTransactionId != null ? 
$ctrl.del.LastAOSPurgeTransactionId : 'N/A'}}</td></tr>
+        </tbody>
+    </table>
+</div>
+</div>
diff --git 
a/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/om-overview.html
 
b/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/om-overview.html
index 703e473f35c..e627aea33a8 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/om-overview.html
+++ 
b/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/om-overview.html
@@ -91,62 +91,3 @@ <h2>Meta-Data Volume Information</h2>
     </tr>
     </tbody>
 </table>
-
-<!-- Only display Deletion Progress on OM leader -->
-<div ng-show="$ctrl.role.Role.trim() === 'LEADER'">
-  <h2>Deletion Progress [{{$ctrl.overview.jmx.MetricsResetTimeStamp ? 'since ' 
+ ($ctrl.overview.jmx.MetricsResetTimeStamp * 1000 | date:'yyyy-MM-dd 
HH:mm:ss') : 'Initializing'}}]
-    &nbsp;&nbsp;•&nbsp;&nbsp;
-    <b>Size Reclaimed:</b> 
{{$ctrl.formatBytes($ctrl.overview.jmx.ReclaimedSizeInInterval)}}
-    &nbsp;&nbsp;•&nbsp;&nbsp;
-    <b>Keys Reclaimed:</b> {{$ctrl.overview.jmx.KeysReclaimedInInterval || 0}}
-  </h2>
-  <div class="mt-4">
-      <div class="mt-3">
-          <div class="col-md-12">
-              <button class="btn btn-sm btn-link p-0" 
ng-click="lastRunDetailsVisible = !lastRunDetailsVisible">
-                  {{ lastRunDetailsVisible ? 'Last Run Details(-)' : 'Last Run 
Details(+)' }}
-              </button>
-          </div>
-          <div ng-show="lastRunDetailsVisible">
-              <div class="mt-3">
-                  <div class="row mb-2" 
ng-if="$ctrl.overview.jmx.KdsCurRunTimestamp">
-                      <div class="col-md-3"><b>Current Run Started:</b></div>
-                      <div 
class="col-md-9">{{$ctrl.convertMsToTime($ctrl.Date.now() - 
$ctrl.overview.jmx.KdsCurRunTimestamp)}} ago</div>
-                  </div>
-                  <div class="row mb-2" 
ng-if="$ctrl.overview.jmx.KdsLastRunTimestamp">
-                      <div class="col-md-3"><b>Last Run:</b></div>
-                      <div 
class="col-md-9">{{$ctrl.convertMsToTime($ctrl.Date.now() - 
$ctrl.overview.jmx.KdsLastRunTimestamp)}} ago</div>
-                  </div>
-              </div>
-              <div style="margin-bottom: 2px;"></div>
-              <table class="table table-sm table-bordered mt-2">
-                  <thead>
-                      <tr>
-                          <th>Store</th>
-                          <th>Reclaimed Size</th>
-                          <th>#Reclaimed Keys</th>
-                          <th>#Iterated Keys</th>
-                          <th>#NotReclaimable Keys (Referred by Snapshots)</th>
-                      </tr>
-                  </thead>
-                  <tbody>
-                      <tr>
-                          <td>Active Object Store</td>
-                          
<td>{{$ctrl.formatBytes($ctrl.overview.jmx.AosReclaimedSizeLast)}}</td>
-                          <td>{{$ctrl.overview.jmx.AosKeysReclaimedLast || 
0}}</td>
-                          <td>{{$ctrl.overview.jmx.AosKeysIteratedLast || 
0}}</td>
-                          <td>{{$ctrl.overview.jmx.AosKeysNotReclaimableLast 
|| 0}}</td>
-                      </tr>
-                      <tr>
-                          <td>Snapshots</td>
-                          
<td>{{$ctrl.formatBytes($ctrl.overview.jmx.SnapReclaimedSizeLast)}}</td>
-                          <td>{{$ctrl.overview.jmx.SnapKeysReclaimedLast || 
0}}</td>
-                          <td>{{$ctrl.overview.jmx.SnapKeysIteratedLast || 
0}}</td>
-                          <td>{{$ctrl.overview.jmx.SnapKeysNotReclaimableLast 
|| 0}}</td>
-                      </tr>
-                  </tbody>
-              </table>
-          </div>
-      </div>
-  </div>
-</div>
diff --git 
a/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/ozoneManager.js
 
b/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/ozoneManager.js
index fdbc300b84d..313c79a3f08 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/ozoneManager.js
+++ 
b/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/ozoneManager.js
@@ -33,6 +33,9 @@
             })
             .when("/ratis_events", {
                 template: "<ratis-events></ratis-events>"
+            })
+            .when("/metrics/deletion", {
+                template: "<om-deletion></om-deletion>"
             });
     });
     angular.module('ozoneManager').component('omSnapshots', {
@@ -270,17 +273,6 @@
         },
         controller: function ($http) {
             var ctrl = this;
-            ctrl.Date = Date;
-
-            ctrl.formatBytes = function(bytes, decimals) {
-               if(bytes == 0) return '0 Bytes';
-               if (!bytes) return 'N/A';
-               var k = 1024, // or 1024 for binary
-                   dm = decimals + 1 || 3,
-                   sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 
'YB'],
-                   i = Math.floor(Math.log(bytes) / Math.log(k));
-               return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + 
sizes[i];
-            }
 
             ctrl.convertMsToTime = function(ms) {
               let seconds = (ms / 1000).toFixed(1);
@@ -310,14 +302,82 @@
                         ctrl.elapsedTime.Value = 
ctrl.convertMsToTime(ctrl.elapsedTime.Value);
                     }
                 });
+        }
+    });
 
-            // Add JMX query to fetch DeletingServiceMetrics data
-            
$http.get("jmx?qry=Hadoop:service=OzoneManager,name=DeletingServiceMetrics")
+    angular.module('ozoneManager').component('omDeletion', {
+        templateUrl: "om-deletion.html",
+        controller: function ($http) {
+            var ctrl = this;
+            ctrl.Date = Date;
+
+            ctrl.formatBytes = function (bytes, decimals) {
+                if (bytes === 0) {
+                    return "0 Bytes";
+                }
+                if (!bytes) {
+                    return "N/A";
+                }
+                var k = 1024,
+                    dm = decimals + 1 || 3,
+                    sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", 
"ZB", "YB"],
+                    i = Math.floor(Math.log(bytes) / Math.log(k));
+                return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " 
+ sizes[i];
+            };
+
+            ctrl.convertMsToTime = function (ms) {
+                var seconds = (ms / 1000).toFixed(1);
+                var minutes = (ms / (1000 * 60)).toFixed(1);
+                var hours = (ms / (1000 * 60 * 60)).toFixed(1);
+                var days = (ms / (1000 * 60 * 60 * 24)).toFixed(1);
+                if (seconds < 60) {
+                    return seconds + " Seconds";
+                } else if (minutes < 60) {
+                    return minutes + " Minutes";
+                } else if (hours < 24) {
+                    return hours + " Hours";
+                } else {
+                    return days + " Days";
+                }
+            };
+
+            ctrl.deletionConfigs = [];
+
+            $http.get("conf?cmd=getPropertyByTag&tags=DELETION")
                 .then(function (result) {
-                    if (result.data.beans && result.data.beans.length > 0) {
-                        // Merge the DeletingServiceMetrics data into the 
existing overview.jmx object
-                        ctrl.overview.jmx = {...ctrl.overview.jmx, 
...result.data.beans[0]};
+                    var deletionByTag = result.data.DELETION || {};
+                    var list = [];
+                    for (var k in deletionByTag) {
+                        if (deletionByTag.hasOwnProperty(k)) {
+                            var pDel = deletionByTag[k];
+                            list.push({
+                                name: pDel.name || k,
+                                value: pDel.value,
+                                description: pDel.description || ""
+                            });
+                        }
                     }
+                    list.sort(function (a, b) {
+                        return a.name.localeCompare(b.name);
+                    });
+                    ctrl.deletionConfigs = list;
+                });
+
+            $http.get("jmx?qry=Ratis:service=RaftServer,group=*,id=*")
+                .then(function (result) {
+                    ctrl.role = result.data.beans[0];
+                });
+
+            
$http.get("jmx?qry=Hadoop:service=OzoneManager,name=DeletingServiceMetrics")
+                .then(function (result) {
+                    ctrl.del = result.data.beans && result.data.beans.length > 0
+                        ? result.data.beans[0] : null;
+                });
+
+            
$http.get("jmx?qry=Hadoop:service=OzoneManager,name=OMPerformanceMetrics")
+                .then(function (result) {
+                    ctrl.perf = result.data.beans && result.data.beans.length 
> 0
+                        ? result.data.beans[0] : null;
                 });
         }
     });


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

Reply via email to