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

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


The following commit(s) were added to refs/heads/2.1 by this push:
     new 65acb18db2 Correctly render null bytes in ListCompactions (#5955)
65acb18db2 is described below

commit 65acb18db20fdd94afdbd8a1cc189d1aa2932968
Author: Dom G. <[email protected]>
AuthorDate: Mon Nov 10 12:06:57 2025 -0500

    Correctly render null bytes in ListCompactions (#5955)
---
 .../shell/commands/ActiveCompactionHelper.java     | 55 +++++++++++++++++++++-
 .../apache/accumulo/test/shell/ShellServerIT.java  |  8 +++-
 2 files changed, 60 insertions(+), 3 deletions(-)

diff --git 
a/shell/src/main/java/org/apache/accumulo/shell/commands/ActiveCompactionHelper.java
 
b/shell/src/main/java/org/apache/accumulo/shell/commands/ActiveCompactionHelper.java
index 62dd93f269..fa93483d24 100644
--- 
a/shell/src/main/java/org/apache/accumulo/shell/commands/ActiveCompactionHelper.java
+++ 
b/shell/src/main/java/org/apache/accumulo/shell/commands/ActiveCompactionHelper.java
@@ -31,8 +31,11 @@ import org.apache.accumulo.core.client.IteratorSetting;
 import org.apache.accumulo.core.client.TableNotFoundException;
 import org.apache.accumulo.core.client.admin.ActiveCompaction;
 import org.apache.accumulo.core.client.admin.InstanceOperations;
+import org.apache.accumulo.core.data.TabletId;
 import org.apache.accumulo.core.util.DurationFormat;
+import org.apache.accumulo.core.util.TextUtil;
 import org.apache.accumulo.shell.Shell;
+import org.apache.hadoop.io.Text;
 
 class ActiveCompactionHelper {
 
@@ -96,13 +99,63 @@ class ActiveCompactionHelper {
       return String.format(
           "%21s | %9s | %5s | %6s | %5s | %5s | %15s | %-40s | %5s | %35s | 
%9s | %s", host, dur,
           ac.getType(), ac.getReason(), shortenCount(ac.getEntriesRead()),
-          shortenCount(ac.getEntriesWritten()), ac.getTable(), ac.getTablet(),
+          shortenCount(ac.getEntriesWritten()), ac.getTable(), 
formatTablet(ac.getTablet()),
           ac.getInputFiles().size(), output, iterList, iterOpts);
     } catch (TableNotFoundException e) {
       return "ERROR " + e.getMessage();
     }
   }
 
+  private static String formatTablet(TabletId tabletId) {
+    if (tabletId == null) {
+      return "";
+    }
+    StringBuilder sb = new StringBuilder();
+    appendEscapedTableId(sb, tabletId.getTable().canonical());
+    appendTabletRow(sb, tabletId.getEndRow());
+    appendTabletRow(sb, tabletId.getPrevEndRow());
+    return sb.toString();
+  }
+
+  private static void appendEscapedTableId(StringBuilder sb, String tableId) {
+    for (int i = 0; i < tableId.length(); i++) {
+      char c = tableId.charAt(i);
+      if (c == '\\') {
+        sb.append("\\\\");
+      } else if (c == ';') {
+        sb.append("\\;");
+      } else {
+        sb.append(c);
+      }
+    }
+  }
+
+  private static void appendTabletRow(StringBuilder sb, Text row) {
+    if (row == null) {
+      sb.append("<");
+      return;
+    }
+    sb.append(';');
+    Text truncated = TextUtil.truncate(row);
+    byte[] bytes = TextUtil.getBytes(truncated);
+    appendEscapedBytes(sb, bytes);
+  }
+
+  private static void appendEscapedBytes(StringBuilder sb, byte[] bytes) {
+    for (byte b : bytes) {
+      int c = b & 0xFF;
+      if (c == '\\') {
+        sb.append("\\\\");
+      } else if (c == ';') {
+        sb.append("\\;");
+      } else if (c >= 32 && c <= 126) {
+        sb.append((char) c);
+      } else {
+        sb.append("\\x").append(String.format("%02X", c));
+      }
+    }
+  }
+
   public static Stream<String> appendHeader(Stream<String> stream) {
     Stream<String> header = Stream.of(String.format(
         " %-21s| %-9s | %-5s | %-6s | %-5s | %-5s | %-15s | %-40s | %-5s | 
%-35s | %-9s | %s",
diff --git 
a/test/src/main/java/org/apache/accumulo/test/shell/ShellServerIT.java 
b/test/src/main/java/org/apache/accumulo/test/shell/ShellServerIT.java
index c275558186..00e7cfdc03 100644
--- a/test/src/main/java/org/apache/accumulo/test/shell/ShellServerIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/shell/ShellServerIT.java
@@ -1447,6 +1447,7 @@ public class ShellServerIT extends SharedMiniClusterBase {
     final String table = getUniqueNames(1)[0];
 
     ts.exec("createtable " + table, true);
+    ts.exec("addsplits -t " + table + " a\0test", true);
     ts.exec(
         "config -t " + table
             + " -s 
table.iterator.minc.slow=30,org.apache.accumulo.test.functional.SlowIterator",
@@ -1460,8 +1461,11 @@ public class ShellServerIT extends SharedMiniClusterBase 
{
     ts.exec("sleep 0.2", true);
     ts.exec("listcompactions", true, "default_tablet");
     String[] lines = ts.output.get().split("\n");
-    String last = lines[lines.length - 1];
-    String[] parts = last.split("\\|");
+    String compaction = Arrays.stream(lines).filter(line -> 
line.contains("default_tablet"))
+        .findFirst().orElseThrow();
+    assertTrue(compaction.contains("\\x00"),
+        "Expected tablet to display \\x00 for null byte: " + compaction);
+    String[] parts = compaction.split("\\|");
     assertEquals(12, parts.length);
     ts.exec("deletetable -f " + table, true);
   }

Reply via email to