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

dlmarion pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git


The following commit(s) were added to refs/heads/main by this push:
     new 1965cc3105 Created Compaction Overview page (#6328)
1965cc3105 is described below

commit 1965cc31055e06d1ef1005c37d7959626f5069b7
Author: Dave Marion <[email protected]>
AuthorDate: Mon Apr 27 16:52:16 2026 -0400

    Created Compaction Overview page (#6328)
    
    This commit changes the labels in the Monitor Activity Menu a bit
    and adds a new Compaction Overview page. The coordinator activity
    table was moved from the Manager page to this new page, along with
    tables for queue activity, running compactions by table and group.
    
    
    Co-authored-by: Dom G. <[email protected]>
---
 .../apache/accumulo/monitor/next/Endpoints.java    |  18 +++
 .../accumulo/monitor/next/SystemInformation.java   | 126 +++++++++++++++++--
 .../accumulo/monitor/next/views/ServersView.java   |  91 +++++++++-----
 .../org/apache/accumulo/monitor/view/WebViews.java |  17 +++
 .../accumulo/monitor/resources/js/coordinator.js   | 134 +++++++++++++++++++++
 .../accumulo/monitor/resources/js/functions.js     |  24 ++++
 .../accumulo/monitor/resources/js/manager.js       |  18 +--
 .../accumulo/monitor/templates/coordinator.ftl     |  54 +++++++++
 .../apache/accumulo/monitor/templates/manager.ftl  |   5 -
 .../apache/accumulo/monitor/templates/navbar.ftl   |   5 +-
 10 files changed, 425 insertions(+), 67 deletions(-)

diff --git 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
index f570d1ecbf..6346f22d10 100644
--- 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
+++ 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
@@ -51,6 +51,8 @@ import org.apache.accumulo.core.process.thrift.MetricResponse;
 import org.apache.accumulo.core.util.compaction.RunningCompactionInfo;
 import org.apache.accumulo.monitor.Monitor;
 import org.apache.accumulo.monitor.next.InformationFetcher.InstanceSummary;
+import 
org.apache.accumulo.monitor.next.SystemInformation.CompactionGroupSummary;
+import 
org.apache.accumulo.monitor.next.SystemInformation.CompactionTableSummary;
 import org.apache.accumulo.monitor.next.SystemInformation.TableSummary;
 import 
org.apache.accumulo.monitor.next.SystemInformation.TimeOrderedRunningCompactionSet;
 import org.apache.accumulo.monitor.next.deployment.DeploymentOverview;
@@ -321,6 +323,22 @@ public class Endpoints {
         .collect(Collectors.toList());
   }
 
+  @GET
+  @Path("compactions/running/group")
+  @Produces(MediaType.APPLICATION_JSON)
+  @Description("Returns number of running major compactions per group")
+  public List<CompactionGroupSummary> getRunningCompactionsPerGroup() {
+    return 
monitor.getInformationFetcher().getSummaryForEndpoint().getRunningCompactionsPerGroup();
+  }
+
+  @GET
+  @Path("compactions/running/table")
+  @Produces(MediaType.APPLICATION_JSON)
+  @Description("Returns number of running major compactions per table")
+  public List<CompactionTableSummary> getRunningCompactionsPerTable() {
+    return 
monitor.getInformationFetcher().getSummaryForEndpoint().getRunningCompactionsPerTable();
+  }
+
   @GET
   @Path("compactions/running/{" + GROUP_PARAM_KEY + "}")
   @Produces(MediaType.APPLICATION_JSON)
diff --git 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
index 2bd4444e42..33493e3265 100644
--- 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
+++ 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
@@ -19,6 +19,7 @@
 package org.apache.accumulo.monitor.next;
 
 import static com.google.common.base.Suppliers.memoize;
+import static org.apache.accumulo.core.metrics.MetricsInfo.QUEUE_TAG_KEY;
 
 import java.nio.ByteBuffer;
 import java.time.Duration;
@@ -26,6 +27,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.EnumMap;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -43,6 +45,7 @@ import java.util.function.Supplier;
 import java.util.stream.Stream;
 
 import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.client.TableNotFoundException;
 import org.apache.accumulo.core.client.admin.TabletAvailability;
 import org.apache.accumulo.core.client.admin.TabletInformation;
 import org.apache.accumulo.core.client.admin.TabletMergeabilityInfo;
@@ -57,7 +60,6 @@ import org.apache.accumulo.core.dataImpl.TabletIdImpl;
 import org.apache.accumulo.core.metadata.SystemTables;
 import org.apache.accumulo.core.metadata.TabletState;
 import org.apache.accumulo.core.metrics.Metric;
-import org.apache.accumulo.core.metrics.MetricsInfo;
 import org.apache.accumulo.core.metrics.flatbuffers.FMetric;
 import org.apache.accumulo.core.metrics.flatbuffers.FTag;
 import org.apache.accumulo.core.process.thrift.MetricResponse;
@@ -65,6 +67,8 @@ import 
org.apache.accumulo.core.spi.balancer.TableLoadBalancer;
 import org.apache.accumulo.core.util.compaction.RunningCompactionInfo;
 import org.apache.accumulo.monitor.next.deployment.DeploymentOverview;
 import org.apache.accumulo.monitor.next.views.ServersView;
+import org.apache.accumulo.monitor.next.views.ServersView.Column;
+import org.apache.accumulo.monitor.next.views.ServersView.ColumnFactory;
 import org.apache.accumulo.server.ServerContext;
 import org.apache.accumulo.server.conf.TableConfiguration;
 import org.apache.accumulo.server.metrics.MetricResponseWrapper;
@@ -352,6 +356,12 @@ public class SystemInformation {
 
   }
 
+  public record CompactionTableSummary(String tableId, String tableName, long 
running) {
+  }
+
+  public record CompactionGroupSummary(String groupId, long running) {
+  }
+
   private static final Logger LOG = 
LoggerFactory.getLogger(SystemInformation.class);
 
   private final DistributionStatisticConfig DSC =
@@ -401,6 +411,9 @@ public class SystemInformation {
   protected final Map<TableId,LongAdder> runningCompactionsPerTable = new 
ConcurrentHashMap<>();
   protected final Map<String,LongAdder> runningCompactionsPerGroup = new 
ConcurrentHashMap<>();
 
+  private final List<CompactionTableSummary> tableCompactions = new 
ArrayList<>();
+  private final List<CompactionGroupSummary> groupCompactions = new 
ArrayList<>();
+
   // Table Information
   private final Map<TableId,TableSummary> tables = new ConcurrentHashMap<>();
   private final Map<TableId,List<TabletInformation>> tablets = new 
ConcurrentHashMap<>();
@@ -449,6 +462,8 @@ public class SystemInformation {
     suggestions.clear();
     runningCompactionsPerGroup.clear();
     runningCompactionsPerTable.clear();
+    tableCompactions.clear();
+    groupCompactions.clear();
     configuredCompactionResourceGroups.clear();
     serverMetricsView.clear();
   }
@@ -490,20 +505,80 @@ public class SystemInformation {
 
   }
 
-  private void createCompactionSummary(MetricResponse response) {
-    if (response.getMetrics() != null) {
-      for (final ByteBuffer binary : response.getMetrics()) {
-        FMetric fm = FMetric.getRootAsFMetric(binary);
-        for (int i = 0; i < fm.tagsLength(); i++) {
-          FTag t = fm.tags(i);
-          if (t.key().equals(MetricsInfo.QUEUE_TAG_KEY)) {
-            queueMetrics
-                .computeIfAbsent(t.value(), (k) -> 
Collections.synchronizedList(new ArrayList<>()))
-                .add(fm);
+  private ServersView createCompactionQueueSummary(final Set<ServerId> 
managers) {
+
+    final Column COMPACTION_QUEUE_COL =
+        new Column(ServersView.RG_COL_KEY, "Compaction Queue", "Compaction 
Queue", "");
+
+    List<ColumnFactory> cols = 
ServersView.columnsFor(ServersView.ServerTable.COORDINATOR_QUEUES);
+
+    // Remove the column mapping for the resource group and replace it so that
+    // the column header reads "Compaction Queue" instead of "Resource Group"
+    int rgIdx = -1;
+    for (int idx = 0; idx < cols.size(); idx++) {
+      if (cols.get(idx).getColumn().key().equals(ServersView.RG_COL_KEY)) {
+        rgIdx = idx;
+        break;
+      }
+    }
+
+    if (rgIdx == -1) {
+      LOG.warn("Did not find Resource Group column to replace column header");
+    } else {
+      cols.remove(rgIdx);
+      cols.set(rgIdx, new ColumnFactory() {
+
+        @Override
+        public Column getColumn() {
+          return COMPACTION_QUEUE_COL;
+        }
+
+        @Override
+        public Object getRowData(ServerId sid, MetricResponse mr,
+            Map<String,List<FMetric>> serverMetrics) {
+          return sid.getResourceGroup().canonical();
+        }
+      });
+    }
+
+    // Construct a Map of MetricResponses by Queue. This method will take
+    // the provided MetricResponse and construct new ones that contain
+    // only the metrics with the "queue.id" tag in addition to the common
+    // server information (address, resource group, etc.).
+    Map<ServerId,MetricResponse> qm = new HashMap<>();
+
+    for (ServerId manager : managers) {
+      MetricResponse response = allMetrics.getIfPresent(manager);
+      if (response.getMetrics() != null) {
+
+        FMetric fm = new FMetric();
+        FTag t = new FTag();
+        for (final ByteBuffer binary : response.getMetrics()) {
+          fm = FMetric.getRootAsFMetric(binary, fm);
+          for (int i = 0; i < fm.tagsLength(); i++) {
+            t = fm.tags(t, i);
+            if (t.key().equals(QUEUE_TAG_KEY)) {
+              String queueName = t.value();
+              // For these MetricResponse objects we are going to put the 
queueId value
+              // in the place of the resource group, we'll update the column 
information
+              // for the resource group below.
+              ServerId sid = new ServerId(manager.getType(), 
ResourceGroupId.of(queueName),
+                  manager.getHost(), manager.getPort());
+              qm.computeIfAbsent(sid, (k) -> new 
MetricResponse(response.getServerType(),
+                  response.getServer(), queueName, response.getTimestamp(), 
new ArrayList<>()))
+                  .addToMetrics(binary);
+              break;
+            }
           }
         }
       }
     }
+
+    if (!qm.isEmpty()) {
+      // Create a ServersView object from the MetricResponse for each queue
+      return new ServersView(qm.keySet(), 0, qm, timestamp.get(), cols);
+    }
+    return new ServersView(Set.of(), 0, Map.of(), timestamp.get(), cols);
   }
 
   public void processResponse(final ServerId server, final MetricResponse 
response) {
@@ -527,7 +602,6 @@ public class SystemInformation {
         break;
       case MANAGER:
         managers.add(server);
-        createCompactionSummary(response);
         break;
       case SCAN_SERVER:
         sservers.computeIfAbsent(response.getResourceGroup(), (rg) -> 
ConcurrentHashMap.newKeySet())
@@ -606,6 +680,7 @@ public class SystemInformation {
             + " group " + balancerRG + ", but there are no TabletServers.");
       }
     }
+
     for (String rg : getResourceGroups()) {
       Set<ServerId> rgCompactors = getCompactorResourceGroupServers(rg);
       List<FMetric> metrics = queueMetrics.get(rg);
@@ -652,6 +727,19 @@ public class SystemInformation {
 
     timestamp.set(System.currentTimeMillis());
 
+    for (Entry<TableId,LongAdder> e : runningCompactionsPerTable.entrySet()) {
+      TableId tid = e.getKey();
+      try {
+        tableCompactions.add(new CompactionTableSummary(tid.canonical(),
+            ctx.getQualifiedTableName(tid), e.getValue().sum()));
+      } catch (TableNotFoundException e1) {
+        LOG.warn("Error converting table id {} to table name, caught 
TableNotFoundException", tid);
+      }
+    }
+
+    runningCompactionsPerGroup
+        .forEach((k, v) -> groupCompactions.add(new CompactionGroupSummary(k, 
v.sum())));
+
     for (final ServerId.Type type : ServerId.Type.values()) {
       long problemHostCount =
           problemHosts.stream().filter(serverId -> serverId.getType() == 
type).count();
@@ -673,6 +761,10 @@ public class SystemInformation {
           cacheServerProcessView(ServersView.ServerTable.MANAGER_FATE, 
servers, problemHostCount);
           cacheServerProcessView(ServersView.ServerTable.MANAGER_COMPACTIONS, 
servers,
               problemHostCount);
+          ServersView coordinatorQueues = 
createCompactionQueueSummary(servers);
+          serverMetricsView.put(ServersView.ServerTable.COORDINATOR_QUEUES,
+              memoize(() -> coordinatorQueues));
+
           break;
         case SCAN_SERVER:
           sservers.values().forEach(servers::addAll);
@@ -706,6 +798,14 @@ public class SystemInformation {
     return this.gc.get();
   }
 
+  public List<CompactionGroupSummary> getRunningCompactionsPerGroup() {
+    return this.groupCompactions;
+  }
+
+  public List<CompactionTableSummary> getRunningCompactionsPerTable() {
+    return this.tableCompactions;
+  }
+
   public Set<ServerId> getCompactorResourceGroupServers(String resourceGroup) {
     return this.compactors.get(resourceGroup);
   }
@@ -783,7 +883,7 @@ public class SystemInformation {
   private void cacheServerProcessView(ServersView.ServerTable table, 
Set<ServerId> servers,
       long problemHostCount) {
     serverMetricsView.put(table, memoize(() -> new ServersView(servers, 
problemHostCount,
-        allMetrics, timestamp.get(), ServersView.columnsFor(table))));
+        allMetrics.asMap(), timestamp.get(), ServersView.columnsFor(table))));
   }
 
   public ServersView getServerProcessView(ServersView.ServerTable table) {
diff --git 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/views/ServersView.java
 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/views/ServersView.java
index 49a8c313d0..4807155ff5 100644
--- 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/views/ServersView.java
+++ 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/views/ServersView.java
@@ -18,6 +18,10 @@
  */
 package org.apache.accumulo.monitor.next.views;
 
+import static 
org.apache.accumulo.monitor.next.views.ServersView.MetricFilterPrefixes.GC_WAL;
+import static 
org.apache.accumulo.monitor.next.views.ServersView.MetricFilterPrefixes.MINC;
+import static 
org.apache.accumulo.monitor.next.views.ServersView.MetricFilterPrefixes.MINC_COMPACTION;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -42,8 +46,6 @@ import 
org.apache.accumulo.server.metrics.MetricResponseWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.github.benmanes.caffeine.cache.Cache;
-
 /**
  * Generic Data Transfer Object (DTO) for a set of Accumulo server processes 
of the same type. The
  * response object contains several fields:
@@ -86,6 +88,7 @@ public class ServersView {
    * directly as the frontend table parameter values.
    */
   public enum ServerTable {
+    COORDINATOR_QUEUES,
     COMPACTORS,
     GC_SUMMARY,
     GC_FILES,
@@ -104,16 +107,21 @@ public class ServersView {
   public static final String ADDR_COL_KEY = "serverAddress";
   public static final String TIME_COL_KEY = "lastContact";
 
+  public static final Column LAST_CONTACT_COLUMN = new Column(TIME_COL_KEY, 
"Last Contact",
+      "Time since the server last responded to the monitor", "duration");
+  public static final Column RG_COLUMN =
+      new Column(RG_COL_KEY, "Resource Group", "Resource Group", "");
+  public static final Column ADDR_COLUMN =
+      new Column(ADDR_COL_KEY, "Server Address", "Server address", "");
+
   /**
    * Common columns that are included in every ServersView table
    */
   private static final List<ColumnFactory> COMMON_COLUMNS = List.of(new 
ColumnFactory() {
-    private final Column column = new Column(TIME_COL_KEY, "Last Contact",
-        "Time since the server last responded to the monitor", "duration");
 
     @Override
     public Column getColumn() {
-      return column;
+      return LAST_CONTACT_COLUMN;
     }
 
     @Override
@@ -122,11 +130,10 @@ public class ServersView {
       return mr == null ? null : System.currentTimeMillis() - 
mr.getTimestamp();
     }
   }, new ColumnFactory() {
-    private final Column column = new Column(RG_COL_KEY, "Resource Group", 
"Resource Group", "");
 
     @Override
     public Column getColumn() {
-      return column;
+      return RG_COLUMN;
     }
 
     @Override
@@ -135,11 +142,10 @@ public class ServersView {
       return sid.getResourceGroup().canonical();
     }
   }, new ColumnFactory() {
-    private final Column column = new Column(ADDR_COL_KEY, "Server Address", 
"Server address", "");
 
     @Override
     public Column getColumn() {
-      return column;
+      return ADDR_COLUMN;
     }
 
     @Override
@@ -155,13 +161,13 @@ public class ServersView {
   public final long timestamp;
 
   public ServersView(final Set<ServerId> servers, final long 
problemServerCount,
-      final Cache<ServerId,MetricResponse> allMetrics, final long timestamp,
+      final Map<ServerId,MetricResponse> allMetrics, final long timestamp,
       final List<ColumnFactory> requestedColumns) {
 
     AtomicInteger serversMissingMetrics = new AtomicInteger(0);
     // Grab the current metrics for each server
     List<ServerMetricRow> serverMetricRows = 
servers.stream().sorted().map(serverId -> {
-      MetricResponse metricResponse = allMetrics.getIfPresent(serverId);
+      MetricResponse metricResponse = allMetrics.get(serverId);
       boolean hasMetricData = hasMetricData(metricResponse);
       Map<String,List<FMetric>> serverMetrics =
           hasMetricData ? metricValuesByName(metricResponse) : Map.of();
@@ -407,6 +413,8 @@ public class ServersView {
     List<ColumnFactory> cols = new ArrayList<>(COMMON_COLUMNS);
 
     switch (table) {
+      case COORDINATOR_QUEUES ->
+        coordinatorQueueMetrics().forEach(m -> cols.add(new 
MetricColumnFactory(m)));
       case COMPACTORS -> compactorMetrics().forEach(m -> cols.add(new 
MetricColumnFactory(m)));
       case GC_SUMMARY -> gcSummaryMetrics().forEach(m -> cols.add(new 
MetricColumnFactory(m)));
       case GC_FILES -> gcFileMetrics().forEach(m -> cols.add(new 
MetricColumnFactory(m)));
@@ -479,63 +487,86 @@ public class ServersView {
     // TODO create scan problems that is a sum of zombie and low memory
   }
 
+  // Filters to use with the metricList method
+  public static enum MetricFilterPrefixes {
+
+    GC_WAL("accumulo.gc.wal."), MINC("accumulo.minc"), 
MINC_COMPACTION("accumulo.compaction.minc");
+
+    String prefix;
+
+    MetricFilterPrefixes(String prefix) {
+      this.prefix = prefix;
+    }
+
+    public String getPrefix() {
+      return prefix;
+    }
+  }
+
   /**
    * The following helper methods are where the metrics included in each table 
are defined as well
    * as their order.
    */
+  private static List<Metric> coordinatorQueueMetrics() {
+    return metricList(m -> !m.getName().startsWith(MINC.getPrefix())
+        && !m.getName().startsWith(MINC_COMPACTION.getPrefix()), 
MetricDocSection.COMPACTION);
+  }
+
   private static List<Metric> compactorMetrics() {
-    return metricList(MetricDocSection.GENERAL_SERVER, 
MetricDocSection.COMPACTION,
+    return metricList(null, MetricDocSection.GENERAL_SERVER, 
MetricDocSection.COMPACTION,
         MetricDocSection.COMPACTOR);
   }
 
   private static List<Metric> gcSummaryMetrics() {
-    return metricList(MetricDocSection.GENERAL_SERVER);
+    return metricList(null, MetricDocSection.GENERAL_SERVER);
   }
 
   private static List<Metric> gcFileMetrics() {
-    return Arrays.stream(Metric.values()).filter(metric -> {
-      String name = metric.getName();
-      return metric.getDocSection() == MetricDocSection.GARBAGE_COLLECTION
-          && !name.startsWith("accumulo.gc.wal.");
-    }).toList();
+    return metricList((m) -> !m.getName().startsWith(GC_WAL.getPrefix()),
+        MetricDocSection.GARBAGE_COLLECTION);
   }
 
   private static List<Metric> gcWalMetrics() {
-    return Arrays.stream(Metric.values())
-        .filter(metric -> metric.getName().startsWith("accumulo.gc.wal."))
+    return Arrays.stream(Metric.values()).filter(m -> 
m.getName().startsWith(GC_WAL.getPrefix()))
         .collect(Collectors.toList());
   }
 
   private static List<Metric> managerMetrics() {
-    return metricList(MetricDocSection.GENERAL_SERVER, 
MetricDocSection.MANAGER);
+    return metricList(null, MetricDocSection.GENERAL_SERVER, 
MetricDocSection.MANAGER);
   }
 
   private static List<Metric> managerFateMetrics() {
-    return metricList(MetricDocSection.FATE);
+    return metricList(null, MetricDocSection.FATE);
   }
 
   private static List<Metric> managerCompactionMetrics() {
-    return metricList(MetricDocSection.COMPACTION);
+    return metricList(m -> !m.getName().startsWith(MINC.getPrefix())
+        && !m.getName().startsWith(MINC_COMPACTION.getPrefix()), 
MetricDocSection.COMPACTION);
   }
 
   private static List<Metric> scanServerMetrics() {
-    return metricList(MetricDocSection.GENERAL_SERVER, 
MetricDocSection.SCAN_SERVER,
+    return metricList(null, MetricDocSection.GENERAL_SERVER, 
MetricDocSection.SCAN_SERVER,
         MetricDocSection.SCAN, MetricDocSection.BLOCK_CACHE);
   }
 
   private static List<Metric> tabletServerMetrics() {
-    return metricList(MetricDocSection.GENERAL_SERVER, 
MetricDocSection.TABLET_SERVER,
+    return metricList(null, MetricDocSection.GENERAL_SERVER, 
MetricDocSection.TABLET_SERVER,
         MetricDocSection.SCAN, MetricDocSection.COMPACTION, 
MetricDocSection.BLOCK_CACHE);
   }
 
   /**
    * @return all the metrics for the given sections
    */
-  private static List<Metric> metricList(MetricDocSection... sections) {
-    Set<MetricDocSection> requestedSections = Set.of(sections);
-    return Arrays.stream(Metric.values())
-        .filter(metric -> requestedSections.contains(metric.getDocSection()))
-        .collect(Collectors.toList());
+  private static List<Metric> metricList(Predicate<Metric> filter, 
MetricDocSection... sections) {
+    Predicate<Metric> sectionPredicate = null;
+    if (sections == null) {
+      sectionPredicate = m -> false;
+    } else {
+      Set<MetricDocSection> requestedSections = Set.of(sections);
+      sectionPredicate = m -> requestedSections.contains(m.getDocSection());
+    }
+    return Arrays.stream(Metric.values()).filter(sectionPredicate)
+        .filter(filter == null ? m -> true : 
filter).collect(Collectors.toList());
   }
 
   public static Number add(Number n1, Number n2) {
diff --git 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
index b142128b79..1f67affd68 100644
--- 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
+++ 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
@@ -258,6 +258,23 @@ public class WebViews {
     return model;
   }
 
+  /**
+   * Returns the compactors template
+   *
+   * @return Compactors model
+   */
+  @GET
+  @Path("coordinator")
+  @Template(name = "/default.ftl")
+  public Map<String,Object> getCompactionOverview() {
+    Map<String,Object> model = getModel();
+    model.put("title", "Compaction Overview");
+    model.put("template", "coordinator.ftl");
+    model.put("js", "coordinator.js");
+
+    return model;
+  }
+
   /**
    * Returns the compactors template
    *
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/coordinator.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/coordinator.js
new file mode 100644
index 0000000000..849288b7ce
--- /dev/null
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/coordinator.js
@@ -0,0 +1,134 @@
+/*
+ * 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
+ *
+ *   https://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.
+ */
+"use strict";
+
+const coordinatorHtmlTable = '#coordinators';
+const queuesHtmlTable = '#coordinator_queues';
+const runningTableHtmlTable = '#table_running';
+const runningQueueHtmlTable = '#queue_running';
+
+var tableRunning;
+var queueRunning;
+
+function getStoredArray(storageKey) {
+  if (!sessionStorage[storageKey]) {
+    return [];
+  }
+  return JSON.parse(sessionStorage[storageKey]);
+}
+
+function refresh() {
+  $.when(getRunningCompactionsByTable(), getRunningCompactionsByGroup(), 
getCoordinatorQueueView(), getManagersCompactionView()).then(function () {
+    refreshTable(coordinatorHtmlTable, MANAGER_COMPACTION_SERVER_PROCESS_VIEW);
+    refreshTable(queuesHtmlTable, COORDINATOR_QUEUE_PROCESS_VIEW);
+    ajaxReloadTable(tableRunning);
+    ajaxReloadTable(queueRunning);
+  }).fail(function () {
+    sessionStorage[MANAGER_COMPACTION_SERVER_PROCESS_VIEW] = JSON.stringify({
+      data: [],
+      columns: [],
+      status: null
+    });
+    sessionStorage[COORDINATOR_QUEUE_PROCESS_VIEW] = JSON.stringify({
+      data: [],
+      columns: [],
+      status: null
+    });
+    sessionStorage[RUNNING_COMPACTIONS_BY_TABLE] = JSON.stringify([]);
+    sessionStorage[RUNNING_COMPACTIONS_BY_GROUP] = JSON.stringify([]);
+    refreshTable(coordinatorHtmlTable, MANAGER_COMPACTION_SERVER_PROCESS_VIEW);
+    refreshTable(queuesHtmlTable, COORDINATOR_QUEUE_PROCESS_VIEW);
+    ajaxReloadTable(tableRunning);
+    ajaxReloadTable(queueRunning);
+    $(coordinatorHtmlTable).hide();
+    $(queuesHtmlTable).hide();
+    $(runningTableHtmlTable).hide();
+    $(runningQueueHtmlTable).hide();
+  });
+}
+
+$(function () {
+  sessionStorage[MANAGER_COMPACTION_SERVER_PROCESS_VIEW] = JSON.stringify({
+    data: [],
+    columns: [],
+    status: null
+  });
+  sessionStorage[COORDINATOR_QUEUE_PROCESS_VIEW] = JSON.stringify({
+    data: [],
+    columns: [],
+    status: null
+  });
+  sessionStorage[RUNNING_COMPACTIONS_BY_TABLE] = JSON.stringify([]);
+  sessionStorage[RUNNING_COMPACTIONS_BY_GROUP] = JSON.stringify([]);
+
+  // Create a table for scans list
+  tableRunning = $(runningTableHtmlTable).DataTable({
+    "ajax": function (data, callback) {
+      callback({
+        data: getStoredArray(RUNNING_COMPACTIONS_BY_TABLE)
+      });
+    },
+    "stateSave": true,
+    "colReorder": true,
+    "columnDefs": [{
+        targets: '_all',
+        defaultContent: '-'
+      },
+      {
+        "targets": 0,
+        "render": function (data, type, row) {
+          if (type === 'display') {
+            data = '<a href="tables/' + row.tableId + '">' + row.tableName + 
'</a>';
+          }
+          return data;
+        }
+      }
+    ],
+    "columns": [{
+        "data": "tableName"
+      },
+      {
+        "data": "running"
+      }
+    ]
+  });
+
+  queueRunning = $(runningQueueHtmlTable).DataTable({
+    "ajax": function (data, callback) {
+      callback({
+        data: getStoredArray(RUNNING_COMPACTIONS_BY_GROUP)
+      });
+    },
+    "stateSave": true,
+    "colReorder": true,
+    "columnDefs": [{
+      targets: '_all',
+      defaultContent: '-'
+    }],
+    "columns": [{
+        "data": "groupId"
+      },
+      {
+        "data": "running"
+      }
+    ]
+  });
+
+  refresh();
+});
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
index 50fb150ed5..2d4a2c3260 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
@@ -26,6 +26,7 @@ const REST_V2_PREFIX = contextPath + 'rest-v2';
 const MANAGER_GOAL_STATE_METRIC = 'accumulo.manager.goal.state';
 
 const COMPACTOR_SERVER_PROCESS_VIEW = 'compactorsView';
+const COORDINATOR_QUEUE_PROCESS_VIEW = 'coordinatorQueueView';
 const GC_SERVER_PROCESS_VIEW = 'gcSummaryView';
 const GC_FILE_SERVER_PROCESS_VIEW = 'gcFileView';
 const GC_WAL_SERVER_PROCESS_VIEW = 'gcWalView';
@@ -34,6 +35,8 @@ const MANAGER_FATE_SERVER_PROCESS_VIEW = 'managersFateView';
 const MANAGER_COMPACTION_SERVER_PROCESS_VIEW = 'managersCompactionView';
 const SCAN_SERVER_PROCESS_VIEW = 'sserversView';
 const TABLET_SERVER_PROCESS_VIEW = 'tserversView';
+const RUNNING_COMPACTIONS_BY_TABLE = 'runningCompactionsByTable';
+const RUNNING_COMPACTIONS_BY_GROUP = 'runningCompactionsByGroup';
 
 // Override Length Menu options for dataTables
 if ($.fn && $.fn.dataTable) {
@@ -686,6 +689,10 @@ function getCompactorsView() {
   return getServerProcessView('COMPACTORS', COMPACTOR_SERVER_PROCESS_VIEW);
 }
 
+function getCoordinatorQueueView() {
+  return getServerProcessView('COORDINATOR_QUEUES', 
COORDINATOR_QUEUE_PROCESS_VIEW);
+}
+
 function getGcView() {
   return getServerProcessView('GC_SUMMARY', GC_SERVER_PROCESS_VIEW);
 }
@@ -773,6 +780,23 @@ function getCompactionsSummary() {
   return getJSONForTable(REST_V2_PREFIX + '/compactions/summary', 
'compactionsSummary');
 }
 
+/**
+ * REST GET call for /compactions/running/table,
+ * stores it on a sessionStorage variable
+ */
+function getRunningCompactionsByTable() {
+  return getJSONForTable(REST_V2_PREFIX + '/compactions/running/table', 
RUNNING_COMPACTIONS_BY_TABLE);
+}
+
+/**
+ * REST GET call for /compactions/running/group,
+ * stores it on a sessionStorage variable
+ */
+function getRunningCompactionsByGroup() {
+  return getJSONForTable(REST_V2_PREFIX + '/compactions/running/group', 
RUNNING_COMPACTIONS_BY_GROUP);
+}
+
+
 /**
  * Returns true if the input is a valid regular expression, false otherwise.
  *
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/manager.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/manager.js
index 58ddbb2f88..0e20a8716d 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/manager.js
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/manager.js
@@ -25,7 +25,6 @@ const managerStateBanner = '#managerStateBanner'
 const managerStateBannerMessage = '#manager-state-message'
 const htmlTable = '#managers'
 const fateHtmlTable = '#managers_fate'
-const compactionHtmlTable = '#managers_compactions'
 
 function updateManagerGoalStateBanner() {
   const goalState = getManagerGoalStateFromSession();
@@ -47,22 +46,19 @@ function refreshManagerBanners() {
     $(runningBanner).show();
     $(htmlTable).hide();
     $(fateHtmlTable).hide();
-    $(compactionHtmlTable).hide();
   } else {
     // otherwise, hide the error banner and show manager table
     $(runningBanner).hide();
     $(fateHtmlTable).show();
     $(htmlTable).show();
-    $(compactionHtmlTable).show();
   }
   updateManagerGoalStateBanner();
 }
 
 function refresh() {
-  $.when(getManagersView(), getManagersFateView(), 
getManagersCompactionView()).then(function () {
+  $.when(getManagersView(), getManagersFateView()).then(function () {
     refreshTable(htmlTable, MANAGER_SERVER_PROCESS_VIEW);
     refreshTable(fateHtmlTable, MANAGER_FATE_SERVER_PROCESS_VIEW);
-    refreshTable(compactionHtmlTable, MANAGER_COMPACTION_SERVER_PROCESS_VIEW);
     refreshManagerBanners();
     refreshBanner(htmlBanner, htmlBannerMessage, 
getStoredStatus(MANAGER_SERVER_PROCESS_VIEW));
   }).fail(function () {
@@ -76,18 +72,11 @@ function refresh() {
       columns: [],
       status: null
     });
-    sessionStorage[MANAGER_COMPACTION_SERVER_PROCESS_VIEW] = JSON.stringify({
-      data: [],
-      columns: [],
-      status: null
-    });
     refreshTable(htmlTable, MANAGER_SERVER_PROCESS_VIEW);
     refreshTable(fateHtmlTable, MANAGER_FATE_SERVER_PROCESS_VIEW);
-    refreshTable(compactionHtmlTable, MANAGER_COMPACTION_SERVER_PROCESS_VIEW);
     $(runningBanner).show();
     $(htmlTable).hide();
     $(fateHtmlTable).hide();
-    $(compactionHtmlTable).hide();
     $(managerStateBanner).hide();
     showBannerError(htmlBanner, htmlBannerMessage);
   });
@@ -104,11 +93,6 @@ $(function () {
     columns: [],
     status: null
   });
-  sessionStorage[MANAGER_COMPACTION_SERVER_PROCESS_VIEW] = JSON.stringify({
-    data: [],
-    columns: [],
-    status: null
-  });
 
   refresh();
 });
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/coordinator.ftl
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/coordinator.ftl
new file mode 100644
index 0000000000..259fc282b8
--- /dev/null
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/coordinator.ftl
@@ -0,0 +1,54 @@
+<#--
+
+    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
+
+      https://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.
+
+-->
+    <br />
+    <table id="coordinators" class="table caption-top table-bordered 
table-striped table-condensed">
+        <caption><span class="table-caption">Compaction Coordinator 
Activity</span><br /></caption>
+        <tbody></tbody>
+    </table>
+    <br />
+    <table id="coordinator_queues" class="table caption-top table-bordered 
table-striped table-condensed">
+        <caption><span class="table-caption">Compaction Coordinator 
Queues</span><br /></caption>
+        <tbody></tbody>
+    </table>
+    <br />
+    <table id="table_running" class="table caption-top table-bordered 
table-striped table-condensed">
+        <caption><span class="table-caption">Running Compactions By 
Table</span><br /></caption>
+        <thead>
+          <tr>
+            <th>Table Name</th>
+            <th>Running Compactions</th>
+          </tr>
+        </thead>
+        <tbody></tbody>
+    </table>
+    <br />
+    <table id="queue_running" class="table caption-top table-bordered 
table-striped table-condensed">
+        <caption><span class="table-caption">Running Compactions By 
Queue</span><br /></caption>
+        <thead>
+          <tr>
+            <th>Queue Name</th>
+            <th>Running Compactions</th>
+          </tr>
+        </thead>
+        <tbody></tbody>
+    </table>
+    <br />
+    
\ No newline at end of file
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/manager.ftl
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/manager.ftl
index d60f17e157..6c1040529c 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/manager.ftl
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/manager.ftl
@@ -32,11 +32,6 @@
         <tbody></tbody>
     </table>
     <br />
-    <table id="managers_compactions" class="table caption-top table-bordered 
table-striped table-condensed">
-        <caption><span class="table-caption">Manager Compaction 
Activity</span><br /></caption>
-        <tbody></tbody>
-    </table>
-    <br />
     <table id="managers_fate" class="table caption-top table-bordered 
table-striped table-condensed">
         <caption><span class="table-caption">Manager Fate Activity</span><br 
/></caption>
         <tbody></tbody>
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/navbar.ftl
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/navbar.ftl
index 3be1576833..1cf41fcd89 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/navbar.ftl
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/navbar.ftl
@@ -54,9 +54,10 @@
                 Activity
               </a>
               <ul class="dropdown-menu col-xs-12" 
aria-labelledby="navbarDropdown">
-                <li><a class="dropdown-item" 
href="ec">Active&nbsp;Compactions</a></li>
-                <li><a class="dropdown-item" 
href="scans">Active&nbsp;Scans</a></li>
                 <li><a class="dropdown-item" 
href="bulkImports">Bulk&nbsp;Imports</a></li>
+                <li><a class="dropdown-item" href="coordinator">Compaction 
Overview</a></li>
+                <li><a class="dropdown-item" href="ec">Compaction 
Details</a></li>
+                <li><a class="dropdown-item" href="scans">Scans</a></li>
               </ul>
             </li>
             <li class="dropdown">


Reply via email to