You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sm...@apache.org on 2021/07/13 14:54:17 UTC
[cassandra] branch cassandra-3.0 updated: Backport CASSANDRA-7950
(Support long names in nodetool output)
This is an automated email from the ASF dual-hosted git repository.
smiklosovic pushed a commit to branch cassandra-3.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/cassandra-3.0 by this push:
new 15c22fa Backport CASSANDRA-7950 (Support long names in nodetool output)
15c22fa is described below
commit 15c22fa2f1e1ec04efb76646fd0ed5ceaff889cf
Author: kurt <ku...@instaclustr.com>
AuthorDate: Wed Mar 14 04:51:08 2018 +0000
Backport CASSANDRA-7950 (Support long names in nodetool output)
this patch also backports chronological sorting of output for compactionhistory command found in versions from 3.2 included (CASSANDRA-10464)
patch by Kurt Greaves; reviewed by Stefan Miklosovic and Ekaterina Dimitrova for CASSANDRA-14162
---
CHANGES.txt | 1 +
.../tools/nodetool/CompactionHistory.java | 79 ++++++++++++--
.../cassandra/tools/nodetool/CompactionStats.java | 46 ++-------
.../cassandra/tools/nodetool/ListSnapshots.java | 13 +--
.../tools/nodetool/formatter/TableBuilder.java | 103 +++++++++++++++++++
.../tools/nodetool/formatter/TableBuilderTest.java | 114 +++++++++++++++++++++
6 files changed, 307 insertions(+), 49 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index eec1e74..a0bd1cf 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
3.0.25:
+ * Support long names in nodetool output (CASSANDRA-14162)
* Handle correctly the exceptions thrown by custom QueryHandler constructors (CASSANDRA-16703)
* Adding columns via ALTER TABLE can generate corrupt sstables (CASSANDRA-16735)
* Add flag to disable ALTER...DROP COMPACT STORAGE statements (CASSANDRA-16733)
diff --git a/src/java/org/apache/cassandra/tools/nodetool/CompactionHistory.java b/src/java/org/apache/cassandra/tools/nodetool/CompactionHistory.java
index 55f7fc5..4624335 100644
--- a/src/java/org/apache/cassandra/tools/nodetool/CompactionHistory.java
+++ b/src/java/org/apache/cassandra/tools/nodetool/CompactionHistory.java
@@ -17,17 +17,22 @@
*/
package org.apache.cassandra.tools.nodetool;
-import static com.google.common.collect.Iterables.toArray;
-import io.airlift.command.Command;
-
import java.io.PrintStream;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
-
import javax.management.openmbean.TabularData;
+import io.airlift.command.Command;
import org.apache.cassandra.tools.NodeProbe;
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
+import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
+
+import static com.google.common.collect.Iterables.toArray;
@Command(name = "compactionhistory", description = "Print history of compaction")
public class CompactionHistory extends NodeToolCmd
@@ -45,15 +50,75 @@ public class CompactionHistory extends NodeToolCmd
return;
}
- String format = "%-41s%-19s%-29s%-26s%-15s%-15s%s%n";
+ TableBuilder table = new TableBuilder();
List<String> indexNames = tabularData.getTabularType().getIndexNames();
- out.printf(format, toArray(indexNames, Object.class));
+ table.add(toArray(indexNames, String.class));
Set<?> values = tabularData.keySet();
+ List<CompactionHistoryRow> chr = new ArrayList<>();
for (Object eachValue : values)
{
List<?> value = (List<?>) eachValue;
- out.printf(format, toArray(value, Object.class));
+ CompactionHistoryRow chc = new CompactionHistoryRow((String)value.get(0),
+ (String)value.get(1),
+ (String)value.get(2),
+ (Long)value.get(3),
+ (Long)value.get(4),
+ (Long)value.get(5),
+ (String)value.get(6));
+ chr.add(chc);
+ }
+ Collections.sort(chr);
+ for (CompactionHistoryRow eachChc : chr)
+ {
+ table.add(eachChc.getAllAsArray());
+ }
+ table.printTo(out);
+ }
+
+ /**
+ * Allows the Compaction History output to be ordered by 'compactedAt' - that is the
+ * time at which compaction finished.
+ */
+ private static class CompactionHistoryRow implements Comparable<CompactionHistoryRow>
+ {
+ private final String id;
+ private final String ksName;
+ private final String cfName;
+ private final long compactedAt;
+ private final long bytesIn;
+ private final long bytesOut;
+ private final String rowMerged;
+
+ CompactionHistoryRow(String id, String ksName, String cfName, long compactedAt, long bytesIn, long bytesOut, String rowMerged)
+ {
+ this.id = id;
+ this.ksName = ksName;
+ this.cfName = cfName;
+ this.compactedAt = compactedAt;
+ this.bytesIn = bytesIn;
+ this.bytesOut = bytesOut;
+ this.rowMerged = rowMerged;
+ }
+
+ public int compareTo(CompactionHistoryRow chc)
+ {
+ return Long.signum(chc.compactedAt - this.compactedAt);
+ }
+
+ public String[] getAllAsArray()
+ {
+ String[] obj = new String[7];
+ obj[0] = this.id;
+ obj[1] = this.ksName;
+ obj[2] = this.cfName;
+ Instant instant = Instant.ofEpochMilli(this.compactedAt);
+ LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
+ obj[3] = ldt.toString();
+ obj[4] = Long.toString(this.bytesIn);
+ obj[5] = Long.toString(this.bytesOut);
+ obj[6] = this.rowMerged;
+ return obj;
}
}
}
diff --git a/src/java/org/apache/cassandra/tools/nodetool/CompactionStats.java b/src/java/org/apache/cassandra/tools/nodetool/CompactionStats.java
index 30830dd..a18ac74 100644
--- a/src/java/org/apache/cassandra/tools/nodetool/CompactionStats.java
+++ b/src/java/org/apache/cassandra/tools/nodetool/CompactionStats.java
@@ -17,23 +17,22 @@
*/
package org.apache.cassandra.tools.nodetool;
-import static java.lang.String.format;
-import io.airlift.command.Command;
-import io.airlift.command.Option;
-
import java.io.PrintStream;
import java.text.DecimalFormat;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import org.apache.cassandra.db.compaction.CompactionInfo;
+import io.airlift.command.Command;
+import io.airlift.command.Option;
+import org.apache.cassandra.db.compaction.CompactionInfo.Unit;
import org.apache.cassandra.db.compaction.CompactionManagerMBean;
import org.apache.cassandra.db.compaction.OperationType;
-import org.apache.cassandra.db.compaction.CompactionInfo.Unit;
import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.tools.NodeProbe;
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
+import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
+
+import static java.lang.String.format;
@Command(name = "compactionstats", description = "Print statistics on compactions")
public class CompactionStats extends NodeToolCmd
@@ -50,14 +49,12 @@ public class CompactionStats extends NodeToolCmd
CompactionManagerMBean cm = probe.getCompactionManagerProxy();
out.println("pending tasks: " + probe.getCompactionMetric("PendingTasks"));
long remainingBytes = 0;
+ TableBuilder table = new TableBuilder();
List<Map<String, String>> compactions = cm.getCompactions();
if (!compactions.isEmpty())
{
int compactionThroughput = probe.getCompactionThroughput();
- List<String[]> lines = new ArrayList<>();
- int[] columnSizes = new int[] { 0, 0, 0, 0, 0, 0, 0, 0 };
-
- addLine(lines, columnSizes, "id", "compaction type", "keyspace", "table", "completed", "total", "unit", "progress");
+ table.add("id", "compaction type", "keyspace", "table", "completed", "total", "unit", "progress");
for (Map<String, String> c : compactions)
{
long total = Long.parseLong(c.get("total"));
@@ -71,24 +68,12 @@ public class CompactionStats extends NodeToolCmd
String totalStr = toFileSize ? FileUtils.stringifyFileSize(total) : Long.toString(total);
String percentComplete = total == 0 ? "n/a" : new DecimalFormat("0.00").format((double) completed / total * 100) + "%";
String id = c.get("compactionId");
- addLine(lines, columnSizes, id, taskType, keyspace, columnFamily, completedStr, totalStr, unit, percentComplete);
+ table.add(id, taskType, keyspace, columnFamily, completedStr, totalStr, unit, percentComplete);
if (taskType.equals(OperationType.COMPACTION.toString()))
remainingBytes += total - completed;
}
- StringBuilder buffer = new StringBuilder();
- for (int columnSize : columnSizes) {
- buffer.append("%");
- buffer.append(columnSize + 3);
- buffer.append("s");
- }
- buffer.append("%n");
- String format = buffer.toString();
-
- for (String[] line : lines)
- {
- out.printf(format, line[0], line[1], line[2], line[3], line[4], line[5], line[6], line[7]);
- }
+ table.printTo(out);
String remainingTime = "n/a";
if (compactionThroughput != 0)
@@ -99,15 +84,4 @@ public class CompactionStats extends NodeToolCmd
out.printf("%25s%10s%n", "Active compaction remaining time : ", remainingTime);
}
}
-
- private void addLine(List<String[]> lines, int[] columnSizes, String... columns)
- {
- String[] newColumns = new String[columns.length];
- for (int i = 0; i < columns.length; i++)
- {
- columnSizes[i] = Math.max(columnSizes[i], columns[i] != null ? columns[i].length() : 1);
- newColumns[i] = columns[i] != null ? columns[i] : "";
- }
- lines.add(newColumns);
- }
}
diff --git a/src/java/org/apache/cassandra/tools/nodetool/ListSnapshots.java b/src/java/org/apache/cassandra/tools/nodetool/ListSnapshots.java
index 18d8053..09e19dd 100644
--- a/src/java/org/apache/cassandra/tools/nodetool/ListSnapshots.java
+++ b/src/java/org/apache/cassandra/tools/nodetool/ListSnapshots.java
@@ -17,18 +17,17 @@
*/
package org.apache.cassandra.tools.nodetool;
-import io.airlift.command.Command;
-
import java.io.PrintStream;
import java.util.List;
import java.util.Map;
import java.util.Set;
-
import javax.management.openmbean.TabularData;
+import io.airlift.command.Command;
import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.tools.NodeProbe;
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
+import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
@Command(name = "listsnapshots", description = "Lists all the snapshots along with the size on disk and true size.")
public class ListSnapshots extends NodeToolCmd
@@ -49,10 +48,11 @@ public class ListSnapshots extends NodeToolCmd
}
final long trueSnapshotsSize = probe.trueSnapshotsSize();
- final String format = "%-40s %-29s %-29s %-19s %-19s%n";
+
+ TableBuilder table = new TableBuilder();
// display column names only once
final List<String> indexNames = snapshotDetails.entrySet().iterator().next().getValue().getTabularType().getIndexNames();
- out.printf(format, (Object[]) indexNames.toArray(new String[indexNames.size()]));
+ table.add(indexNames.toArray(new String[indexNames.size()]));
for (final Map.Entry<String, TabularData> snapshotDetail : snapshotDetails.entrySet())
{
@@ -60,9 +60,10 @@ public class ListSnapshots extends NodeToolCmd
for (Object eachValue : values)
{
final List<?> value = (List<?>) eachValue;
- out.printf(format, value.toArray(new Object[value.size()]));
+ table.add(value.toArray(new String[value.size()]));
}
}
+ table.printTo(out);
out.println("\nTotal TrueDiskSpaceUsed: " + FileUtils.stringifyFileSize(trueSnapshotsSize) + "\n");
}
diff --git a/src/java/org/apache/cassandra/tools/nodetool/formatter/TableBuilder.java b/src/java/org/apache/cassandra/tools/nodetool/formatter/TableBuilder.java
new file mode 100644
index 0000000..a56e52e
--- /dev/null
+++ b/src/java/org/apache/cassandra/tools/nodetool/formatter/TableBuilder.java
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+package org.apache.cassandra.tools.nodetool.formatter;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import javax.annotation.Nonnull;
+
+/**
+ * Build and print table.
+ *
+ * usage:
+ * <pre>
+ * {@code
+ * TableBuilder table = new TableBuilder();
+ * for (String[] row : data)
+ * {
+ * table.add(row);
+ * }
+ * table.print(System.out);
+ * }
+ * </pre>
+ */
+public class TableBuilder
+{
+ // column delimiter char
+ private final char columnDelimiter;
+
+ private int[] maximumColumnWidth;
+ private final List<String[]> rows = new ArrayList<>();
+
+ public TableBuilder()
+ {
+ this(' ');
+ }
+
+ public TableBuilder(char columnDelimiter)
+ {
+ this.columnDelimiter = columnDelimiter;
+ }
+
+ public void add(@Nonnull String... row)
+ {
+ Objects.requireNonNull(row);
+
+ if (rows.isEmpty())
+ {
+ maximumColumnWidth = new int[row.length];
+ }
+
+ // expand max column widths if given row has more columns
+ if (row.length > maximumColumnWidth.length)
+ {
+ int[] tmp = new int[row.length];
+ System.arraycopy(maximumColumnWidth, 0, tmp, 0, maximumColumnWidth.length);
+ maximumColumnWidth = tmp;
+ }
+ // calculate maximum column width
+ int i = 0;
+ for (String col : row)
+ {
+ maximumColumnWidth[i] = Math.max(maximumColumnWidth[i], col != null ? col.length() : 1);
+ i++;
+ }
+ rows.add(row);
+ }
+
+ public void printTo(PrintStream out)
+ {
+ if (rows.isEmpty())
+ return;
+
+ for (String[] row : rows)
+ {
+ for (int i = 0; i < maximumColumnWidth.length; i++)
+ {
+ String col = i < row.length ? row[i] : "";
+ out.print(String.format("%-" + maximumColumnWidth[i] + 's', col != null ? col : ""));
+ if (i < maximumColumnWidth.length - 1)
+ out.print(columnDelimiter);
+ }
+ out.println();
+ }
+ }
+}
diff --git a/test/unit/org/apache/cassandra/tools/nodetool/formatter/TableBuilderTest.java b/test/unit/org/apache/cassandra/tools/nodetool/formatter/TableBuilderTest.java
new file mode 100644
index 0000000..9782b5b
--- /dev/null
+++ b/test/unit/org/apache/cassandra/tools/nodetool/formatter/TableBuilderTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+package org.apache.cassandra.tools.nodetool.formatter;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class TableBuilderTest
+{
+ @Test
+ public void testEmptyRow()
+ {
+ TableBuilder table = new TableBuilder();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (PrintStream out = new PrintStream(baos))
+ {
+ table.printTo(out);
+ }
+ assertEquals("", baos.toString());
+ }
+
+ @Test
+ public void testOneRow()
+ {
+ TableBuilder table = new TableBuilder();
+
+ table.add("a", "bb", "ccc");
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (PrintStream out = new PrintStream(baos))
+ {
+ table.printTo(out);
+ }
+ assertEquals(String.format("a bb ccc%n"), baos.toString());
+ }
+
+ @Test
+ public void testRows()
+ {
+ TableBuilder table = new TableBuilder();
+ table.add("a", "bb", "ccc");
+ table.add("aaa", "bb", "c");
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (PrintStream out = new PrintStream(baos))
+ {
+ table.printTo(out);
+ }
+ assertEquals(String.format("a bb ccc%naaa bb c %n"), baos.toString());
+ }
+
+ @Test
+ public void testNullColumn()
+ {
+ TableBuilder table = new TableBuilder();
+ table.add("a", "b", "c");
+ table.add("a", null, "c");
+ table.add("a", null, null);
+ table.add(null, "b", "c");
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (PrintStream out = new PrintStream(baos))
+ {
+ table.printTo(out);
+ }
+ assertEquals(String.format("a b c%na c%na %n b c%n"), baos.toString());
+ }
+
+ @Test
+ public void testRowsOfDifferentSize()
+ {
+ TableBuilder table = new TableBuilder();
+ table.add("a", "b", "c");
+ table.add("a", "b", "c", "d", "e");
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (PrintStream out = new PrintStream(baos))
+ {
+ table.printTo(out);
+ }
+ assertEquals(baos.toString(), String.format("a b c %na b c d e%n"), baos.toString());
+ }
+
+ @Test
+ public void testDelimiter()
+ {
+ TableBuilder table = new TableBuilder('\t');
+
+ table.add("a", "bb", "ccc");
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (PrintStream out = new PrintStream(baos))
+ {
+ table.printTo(out);
+ }
+ assertEquals(String.format("a\tbb\tccc%n"), baos.toString());
+ }
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org