This is an automated email from the ASF dual-hosted git repository. domgarguilo 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 2d2cd58bdf Use new REST API for tables page (#5351) 2d2cd58bdf is described below commit 2d2cd58bdfcc9763191eb789beae39e998da45ff Author: Dom G. <domgargu...@apache.org> AuthorDate: Wed Mar 5 17:34:57 2025 -0500 Use new REST API for tables page (#5351) --- .../apache/accumulo/monitor/next/Endpoints.java | 25 +-- .../accumulo/monitor/next/InformationFetcher.java | 28 ++-- .../accumulo/monitor/next/SystemInformation.java | 26 +++- .../org/apache/accumulo/monitor/view/WebViews.java | 11 +- .../accumulo/monitor/resources/js/functions.js | 12 +- .../apache/accumulo/monitor/resources/js/table.js | 168 ++++++++++++--------- .../apache/accumulo/monitor/templates/table.ftl | 54 +++++-- .../apache/accumulo/monitor/templates/tables.ftl | 23 ++- 8 files changed, 211 insertions(+), 136 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 518d2dcf01..629b3fa512 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 @@ -44,6 +44,7 @@ import org.apache.accumulo.core.Constants; import org.apache.accumulo.core.client.admin.TabletInformation; import org.apache.accumulo.core.client.admin.servers.ServerId; import org.apache.accumulo.core.compaction.thrift.TExternalCompaction; +import org.apache.accumulo.core.data.TableId; import org.apache.accumulo.core.metrics.flatbuffers.FMetric; import org.apache.accumulo.core.process.thrift.MetricResponse; import org.apache.accumulo.monitor.Monitor; @@ -313,31 +314,33 @@ public class Endpoints { @GET @Path("tables") @Produces(MediaType.APPLICATION_JSON) - @Description("Returns a map of table name to table details") - public Map<String,TableSummary> getTables() { + @Description("Returns a map of TableId to table details") + public Map<TableId,TableSummary> getTables() { return monitor.getInformationFetcher().getSummary().getTables(); } @GET - @Path("tables/{name}") + @Path("tables/{tableId}") @Produces(MediaType.APPLICATION_JSON) - @Description("Returns table details for the supplied table name") - public TableSummary getTable(@PathParam("name") String tableName) { - TableSummary ts = monitor.getInformationFetcher().getSummary().getTables().get(tableName); + @Description("Returns table details for the supplied TableId") + public TableSummary getTable(@PathParam("tableId") String tableId) { + TableSummary ts = + monitor.getInformationFetcher().getSummary().getTables().get(TableId.of(tableId)); if (ts == null) { - throw new NotFoundException(tableName + " not found"); + throw new NotFoundException(tableId + " not found"); } return ts; } @GET - @Path("tables/{name}/tablets") + @Path("tables/{tableId}/tablets") @Produces(MediaType.APPLICATION_JSON) @Description("Returns tablet details for the supplied table name") - public List<TabletInformation> getTablets(@PathParam("name") String tableName) { - List<TabletInformation> ti = monitor.getInformationFetcher().getSummary().getTablets(tableName); + public List<TabletInformation> getTablets(@PathParam("tableId") String tableId) { + List<TabletInformation> ti = + monitor.getInformationFetcher().getSummary().getTablets(TableId.of(tableId)); if (ti == null) { - throw new NotFoundException(tableName + " not found"); + throw new NotFoundException(tableId + " not found"); } return ti; } diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java index 049be3b420..11a1b3f23a 100644 --- a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java +++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java @@ -43,6 +43,7 @@ import org.apache.accumulo.core.compaction.thrift.CompactionCoordinatorService; import org.apache.accumulo.core.compaction.thrift.TExternalCompactionList; import org.apache.accumulo.core.conf.Property; import org.apache.accumulo.core.data.Range; +import org.apache.accumulo.core.data.TableId; import org.apache.accumulo.core.process.thrift.MetricResponse; import org.apache.accumulo.core.process.thrift.ServerProcessService.Client; import org.apache.accumulo.core.rpc.ThriftUtil; @@ -139,27 +140,28 @@ public class InformationFetcher implements RemovalListener<ServerId,MetricRespon private class TableInformationFetcher implements Runnable { private final ServerContext ctx; - private final String table; + private final TableId tableId; private final SystemInformation summary; - private TableInformationFetcher(ServerContext ctx, String tableName, - SystemInformation summary) { + private TableInformationFetcher(ServerContext ctx, TableId tableId, SystemInformation summary) { this.ctx = ctx; - this.table = tableName; + this.tableId = tableId; this.summary = summary; } @Override public void run() { - try (Stream<TabletInformation> tablets = - this.ctx.tableOperations().getTabletInformation(table, new Range())) { - tablets.forEach(t -> summary.processTabletInformation(table, t)); + try { + final String tableName = ctx.getTableName(tableId); + try (Stream<TabletInformation> tablets = + this.ctx.tableOperations().getTabletInformation(tableName, new Range())) { + tablets.forEach(t -> summary.processTabletInformation(tableId, tableName, t)); + } } catch (TableNotFoundException e) { - LOG.warn( - "TableNotFoundException thrown while trying to gather information for table: " + table, - e); + LOG.warn("TableNotFoundException thrown while trying to gather information for TableId: {}", + tableId, e); } catch (Exception e) { - LOG.warn("Interrupted while trying to gather information for table: {}", table, e); + LOG.warn("Interrupted while trying to gather information for TableId: {}", tableId, e); } } } @@ -292,8 +294,8 @@ public class InformationFetcher implements RemovalListener<ServerId,MetricRespon futures.add(this.pool.submit(new CompactionListFetcher(summary))); // Fetch Tablet / Tablet information from the metadata table - for (String tName : this.ctx.tableOperations().list()) { - futures.add(this.pool.submit(new TableInformationFetcher(this.ctx, tName, summary))); + for (TableId tableId : this.ctx.getTableNameToIdMap().values()) { + futures.add(this.pool.submit(new TableInformationFetcher(this.ctx, tableId, summary))); } long monitorFetchTimeout = 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 875a64b93c..b3add07130 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 @@ -40,6 +40,7 @@ import org.apache.accumulo.core.client.admin.TabletMergeabilityInfo; import org.apache.accumulo.core.client.admin.servers.ServerId; import org.apache.accumulo.core.compaction.thrift.TExternalCompaction; import org.apache.accumulo.core.compaction.thrift.TExternalCompactionList; +import org.apache.accumulo.core.data.TableId; import org.apache.accumulo.core.data.TabletId; import org.apache.accumulo.core.dataImpl.KeyExtent; import org.apache.accumulo.core.dataImpl.TabletIdImpl; @@ -154,6 +155,11 @@ public class SystemInformation { private final AtomicLong totalHostedTablets = new AtomicLong(); private final AtomicLong totalSuspendedTablets = new AtomicLong(); private final AtomicLong totalUnassignedTablets = new AtomicLong(); + private String tableName; + + public TableSummary(String tableName) { + this.tableName = tableName; + } public long getTotalEntries() { return totalEntries.get(); @@ -207,6 +213,10 @@ public class SystemInformation { return totalUnassignedTablets.get(); } + public String getTableName() { + return tableName; + } + public void addTablet(TabletInformation info) { totalEntries.addAndGet(info.getEstimatedEntries()); totalSizeOnDisk.addAndGet(info.getEstimatedSize()); @@ -327,8 +337,8 @@ public class SystemInformation { new AtomicReference<>(); // Table Information - private final Map<String,TableSummary> tables = new ConcurrentHashMap<>(); - private final Map<String,List<TabletInformation>> tablets = new ConcurrentHashMap<>(); + private final Map<TableId,TableSummary> tables = new ConcurrentHashMap<>(); + private final Map<TableId,List<TabletInformation>> tablets = new ConcurrentHashMap<>(); // Deployment Overview private final Map<String,Map<String,ProcessSummary>> deployment = new ConcurrentHashMap<>(); @@ -460,11 +470,11 @@ public class SystemInformation { oldestCompactions.set(running); } - public void processTabletInformation(String tableName, TabletInformation info) { + public void processTabletInformation(TableId tableId, String tableName, TabletInformation info) { final SanitizedTabletInformation sti = new SanitizedTabletInformation(info); - tablets.computeIfAbsent(tableName, (t) -> Collections.synchronizedList(new ArrayList<>())) + tablets.computeIfAbsent(tableId, (t) -> Collections.synchronizedList(new ArrayList<>())) .add(sti); - tables.computeIfAbsent(tableName, (t) -> new TableSummary()).addTablet(sti); + tables.computeIfAbsent(tableId, (t) -> new TableSummary(tableName)).addTablet(sti); if (sti.getEstimatedEntries() == 0) { suggestions.add("Tablet " + sti.getTabletId().toString() + " (tid: " + sti.getTabletId().getTable() + ") may have zero entries and could be merged."); @@ -582,12 +592,12 @@ public class SystemInformation { return list.getCompactions(); } - public Map<String,TableSummary> getTables() { + public Map<TableId,TableSummary> getTables() { return this.tables; } - public List<TabletInformation> getTablets(String table) { - return this.tablets.get(table); + public List<TabletInformation> getTablets(TableId tableId) { + return this.tablets.get(tableId); } public Map<String,Map<String,ProcessSummary>> getDeploymentOverview() { 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 802fd5bdec..35d35a1697 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 @@ -279,24 +279,23 @@ public class WebViews { /** * Returns participating tservers template * - * @param tableID Table ID for participating tservers + * @param tableId Table ID for participating tservers * @return Participating tservers model */ @GET - @Path("tables/{tableID}") + @Path("tables/{tableId}") @Template(name = "/default.ftl") public Map<String,Object> getTables( - @PathParam("tableID") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX_TABLE_ID) String tableID) + @PathParam("tableId") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX_TABLE_ID) String tableId) throws TableNotFoundException { - - String tableName = monitor.getContext().getTableName(TableId.of(tableID)); + String tableName = monitor.getContext().getTableName(TableId.of(tableId)); Map<String,Object> model = getModel(); model.put("title", "Table Status"); model.put("template", "table.ftl"); model.put("js", "table.js"); - model.put("tableID", tableID); + model.put("tableId", tableId); model.put("table", tableName); return model; 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 fa1e9afb4e..639d935cf8 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 @@ -25,7 +25,7 @@ // Suffixes for quantity var QUANTITY_SUFFIX = ['', 'K', 'M', 'B', 'T', 'e15', 'e18', 'e21']; // Suffixes for size -var SIZE_SUFFIX = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']; +var SIZE_SUFFIX = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB']; /** * Initializes Auto Refresh to false if it is not set, @@ -103,14 +103,14 @@ function bigNumber(big, suffixes, base) { } /** - * Converts a number to a size with suffix + * Converts a size in bytes to a human-readable string with appropriate units. * - * @param {number} size Number to convert - * @return {string} Number with suffix added + * @param {number} size - The size in bytes to be converted. + * @returns {string} The human-readable string representation of the size. */ function bigNumberForSize(size) { - if (size === null) { - size = 0; + if (size === 0) { + return '0B'; } return bigNumber(size, SIZE_SUFFIX, 1024); } diff --git a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/table.js b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/table.js index fc39d67919..0734b573f6 100644 --- a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/table.js +++ b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/table.js @@ -19,6 +19,7 @@ "use strict"; var tableServersTable; +var tabletsTable; /** * Makes the REST calls, generates the tables with the new information @@ -34,24 +35,17 @@ function refresh() { refreshTable(); } -function getQueuedAndRunning(data) { - return `${data.running}(${data.queued})`; -} - /** - * Initialize the table - * - * @param {String} tableID the accumulo table ID + * Makes the REST call to fetch tablet details and render them. */ -function initTableServerTable(tableID) { +function initTabletsTable(tableId) { + var tabletsUrl = '/rest-v2/tables/' + tableId + '/tablets'; + console.debug('Fetching tablets info from: ' + tabletsUrl); - const url = '/rest/tables/' + tableID; - console.debug('REST url used to fetch data for table.js DataTable: ' + url); - - tableServersTable = $('#participatingTServers').DataTable({ + tabletsTable = $('#tabletsList').DataTable({ "ajax": { - "url": url, - "dataSrc": "servers" + "url": tabletsUrl, + "dataSrc": "" }, "stateSave": true, "columnDefs": [{ @@ -64,106 +58,142 @@ function initTableServerTable(tableID) { } }, { - "targets": "duration", + "targets": "big-size", "render": function (data, type) { if (type === 'display') { - data = timeDuration(data); + data = bigNumberForSize(data); } return data; } + } + ], + "columns": [{ + "data": "tabletId", + "title": "Tablet ID" }, { - "targets": "percent", - "render": function (data, type) { - if (type === 'display') { - data = Math.round(data * 100) + '%'; - } - return data; - } + "data": "estimatedSize", + "title": "Estimated Size" }, - // ensure these 3 columns are sorted by the 2 numeric values that comprise the combined string - // instead of sorting them lexicographically by the string itself. - // Specifically: 'targets' column will use the values in the 'orderData' columns - - // scan column will be sorted by number of running, then by number of queued { - "targets": [7], - "type": "numeric", - "orderData": [13, 14] + "data": "estimatedEntries", + "title": "Estimated Entries" }, - // minor compaction column will be sorted by number of running, then by number of queued { - "targets": [8], - "type": "numeric", - "orderData": [15, 16] + "data": "tabletAvailability", + "title": "Availability" }, - ], - "columns": [{ - "data": "hostname", - "type": "html", - "render": function (data, type, row) { - if (type === 'display') { - data = `<a href="/tservers?s=${row.id}">${data}</a>`; - } - return data; - } + { + "data": "numFiles", + "title": "Files" }, { - "data": "tablets" + "data": "numWalLogs", + "title": "WALs" }, { - "data": "lastContact" + "data": "location", + "title": "Location" + } + ] + }); +} + +/** + * Initialize the table + * + * @param {String} tableId the accumulo table ID + */ +function initTableServerTable(tableId) { + const url = '/rest-v2/tables/' + tableId; + console.debug('REST url used to fetch summary data: ' + url); + + tableServersTable = $('#participatingTServers').DataTable({ + "ajax": { + "url": url, + "dataSrc": function (json) { + // Convert the JSON object into an array for DataTables consumption. + return [json]; + } + }, + "stateSave": true, + "searching": false, + "paging": false, + "info": false, + "columnDefs": [{ + "targets": "big-num", + "render": function (data, type) { + if (type === 'display') { + data = bigNumberForQuantity(data); + } + return data; + } }, { - "data": "entries" + "targets": "big-size", + "render": function (data, type) { + if (type === 'display') { + data = bigNumberForSize(data); + } + return data; + } + } + ], + "columns": [{ + "data": "totalEntries", + "title": "Entry Count" }, { - "data": "ingest" + "data": "totalSizeOnDisk", + "title": "Size on disk" }, { - "data": "query" + "data": "totalFiles", + "title": "File Count" }, { - "data": "holdtime" + "data": "totalWals", + "title": "WAL Count" }, { - "data": function (row) { - return getQueuedAndRunning(row.compactions.scans); - } + "data": "totalTablets", + "title": "Total Tablet Count" }, { - "data": function (row) { - return getQueuedAndRunning(row.compactions.minor); - } + "data": "availableAlways", + "title": "Always Hosted Count" }, { - "data": "indexCacheHitRate" + "data": "availableOnDemand", + "title": "On Demand Count" }, { - "data": "dataCacheHitRate" + "data": "availableNever", + "title": "Never Hosted Count" }, { - "data": "osload" + "data": "totalAssignedTablets", + "title": "Assigned Tablet Count" }, { - "data": "scansRunning", - "visible": false + "data": "totalAssignedToDeadServerTablets", + "title": "Tablets Assigned to Dead Servers Count" }, { - "data": "scansQueued", - "visible": false + "data": "totalHostedTablets", + "title": "Hosted Tablet Count" }, { - "data": "minorRunning", - "visible": false + "data": "totalSuspendedTablets", + "title": "Suspended Tablet Count" }, { - "data": "minorQueued", - "visible": false + "data": "totalUnassignedTablets", + "title": "Unassigned Tablet Count" } ] }); refreshTable(); - + initTabletsTable(tableId); } diff --git a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/table.ftl b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/table.ftl index 0cafbc5811..5c034e432e 100644 --- a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/table.ftl +++ b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/table.ftl @@ -20,38 +20,60 @@ --> <script> /** - * Creates participating Tservers initial table, passes the tableID from the template + * Creates participating Tservers initial table, passes the tableId from the template */ $(function () { - initTableServerTable('${tableID}'); + initTableServerTable('${tableId}'); }); </script> <div class="row"> <div class="col-xs-12"> - <h3>${title}</h3> + <h3>Details for table ${table} <small>(ID: ${tableId})</small></h3> </div> </div> <div class="row"> <div class="col-xs-12"> <table id="participatingTServers" class="table caption-top table-bordered table-striped table-condensed"> - <caption><span class="table-caption">${table}</span></caption> + <caption><span class="table-caption">Table Summary</span></caption> <thead> <tr> - <th>Server </th> - <th class="big-num">Hosted<br />Tablets </th> - <th class="duration">Last Contact </th> - <th class="big-num" title="Key/value pairs over each instance, table or tablet.">Entries </th> - <th class="big-num" title="The number of Key/Value pairs inserted. (Note that deletes are considered inserted)">Ingest </th> - <th class="big-num" title="The number of key/value pairs returned to clients. (Not the number of scans)">Query </th> - <th class="duration" title="The amount of time live ingest operations (mutations, batch writes) have been waiting for the tserver to free up memory.">Hold Time </th> - <th title="Information about the scans threads. Shows how many threads are running and, in parentheses, how much work is queued for the threads.">Scans </th> - <th title="The action of flushing memory to disk. Multiple tablets can be compacted simultaneously, but sometimes they must wait for resources to be available. The number of tablets waiting for compaction is in parentheses.">Minor Compactions </th> - <th class="percent" title="The recent index cache hit rate.">Index Cache<br />Hit Rate </th> - <th class="percent" title="The recent data cache hit rate.">Data Cache<br />Hit Rate </th> - <th class="big-num" title="The Unix one minute load average. The average number of processes in the run queue over a one minute interval.">OS Load </th> + <th class="big-num">Entry Count</th> + <th class="big-size">Size on disk</th> + <th class="big-num">File Count</th> + <th class="big-num">WAL Count</th> + <th class="big-num">Total Tablet Count</th> + <th class="big-num">Always Hosted Count</th> + <th class="big-num">On Demand Count</th> + <th class="big-num">Never Hosted Count</th> + <th class="big-num">Assigned Count</th> + <th class="big-num">Assigned To Dead Server Tablets</th> + <th class="big-num">Hosted Tablets</th> + <th class="big-num">Suspended Tablets</th> + <th class="big-num">Unassigned Tablets</th> </tr> </thead> <tbody></tbody> </table> </div> </div> + <br><br> + <!-- Section for tablets details DataTable --> + <div class="row"> + <div class="col-xs-12"> + <table id="tabletsList" class="table caption-top table-bordered table-striped table-condensed"> + <caption><span class="table-caption">Tablet Details</span></caption> + <thead> + <tr> + <th>Tablet ID</th> + <th class="big-size">Estimated Size</th> + <th class="big-num">Estimated Entries</th> + <th>Availability</th> + <th class="big-num">Files</th> + <th class="big-num">WALs</th> + <th>Location</th> + </tr> + </thead> + <tbody></tbody> + </table> + </div> + </div> \ No newline at end of file diff --git a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/tables.ftl b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/tables.ftl index 3b339048ed..dcbfc71900 100644 --- a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/tables.ftl +++ b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/tables.ftl @@ -32,7 +32,7 @@ "url": "/rest-v2/tables", "dataSrc": function (json) { return Object.keys(json).map(function (key) { - json[key].tablename = key; + json[key].tableId = key; return json[key]; }); } @@ -40,22 +40,31 @@ "stateSave": true, "columnDefs": [ { - "type": "num", "targets": "big-num", - "render": function (data, type, row) { - if (type === 'display') + "render": function (data, type) { + if (type === 'display') { data = bigNumberForQuantity(data); + } + return data; + } + }, + { + "targets": "big-size", + "render": function (data, type) { + if (type === 'display') { + data = bigNumberForSize(data); + } return data; } } ], "columns": [ { - "data": "tablename", + "data": "tableName", "type": "html", "render": function (data, type, row, meta) { if (type === 'display') { - data = '<a href="/tables/' + row.tablename + '">' + row.tablename + '</a>'; + data = '<a href="/tables/' + row.tableId + '">' + row.tableName + '</a>'; } return data; } @@ -101,7 +110,7 @@ <th title="Table Name">Table Name</th> <th title="Tables are broken down into ranges of rows called tablets." class="big-num">Tablets</th> <th title="Key/value pairs over each instance, table or tablet." class="big-num">Entries</th> - <th title="Total size on disk." class="big-num">Size on Disk</th> + <th title="Total size on disk." class="big-size">Size on Disk</th> <th title="Total number of files." class="big-num">Files</th> <th title="Total number of WALs." class="big-num">WALs</th> <th title="Number of tablets that are always hosted." class="big-num">Always Available</th>