mirror of https://github.com/apache/cassandra
Fix multi DC nodetool status output
Patch by Chris Lohfink; Reviewed by Brandon Williams for CASSANDRA-15305
This commit is contained in:
commit
d9798369dd
|
|
@ -1,4 +1,5 @@
|
|||
4.0-alpha4
|
||||
* Fix multi DC nodetool status output (CASSANDRA-15305)
|
||||
* Added documentation covering new Netty based internode messaging (CASSANDRA-15478)
|
||||
* Add documentation of hints (CASSANDRA-15491)
|
||||
* updateCoordinatorWriteLatencyTableMetric can produce misleading metrics (CASSANDRA-15569)
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ public class DescribeCluster extends NodeToolCmd
|
|||
|
||||
ArrayListMultimap<InetAddressAndPort, HostStatWithPort> hostToTokens = ArrayListMultimap.create();
|
||||
for (HostStatWithPort stat : dc.getValue())
|
||||
hostToTokens.put(stat.endpoint, stat);
|
||||
hostToTokens.put(stat.endpointWithPort, stat);
|
||||
|
||||
int totalNodes = 0; // total number of nodes in a datacenter
|
||||
int downNodes = 0; // number of down nodes in a datacenter
|
||||
|
|
|
|||
|
|
@ -20,25 +20,28 @@ package org.apache.cassandra.tools.nodetool;
|
|||
|
||||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
|
||||
public class HostStatWithPort
|
||||
public class HostStatWithPort extends HostStat
|
||||
{
|
||||
public final InetAddressAndPort endpoint;
|
||||
public final boolean resolveIp;
|
||||
public final Float owns;
|
||||
public final String token;
|
||||
public final InetAddressAndPort endpointWithPort;
|
||||
|
||||
public HostStatWithPort(String token, InetAddressAndPort endpoint, boolean resolveIp, Float owns)
|
||||
{
|
||||
this.token = token;
|
||||
this.endpoint = endpoint;
|
||||
this.resolveIp = resolveIp;
|
||||
this.owns = owns;
|
||||
super(token, endpoint.address, resolveIp, owns);
|
||||
this.endpointWithPort = endpoint;
|
||||
}
|
||||
|
||||
public String ipOrDns()
|
||||
{
|
||||
return ipOrDns(true);
|
||||
}
|
||||
|
||||
public String ipOrDns(boolean withPort)
|
||||
{
|
||||
if (!withPort)
|
||||
return super.ipOrDns();
|
||||
|
||||
return resolveIp ?
|
||||
endpoint.address.getHostName() + ":" + endpoint.port :
|
||||
endpoint.toString();
|
||||
endpointWithPort.address.getHostName() + ':' + endpointWithPort.port :
|
||||
endpointWithPort.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import java.net.InetAddress;
|
|||
import java.net.UnknownHostException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
|
|
@ -67,118 +68,72 @@ public class Status extends NodeToolCmd
|
|||
epSnitchInfo = probe.getEndpointSnitchInfoProxy();
|
||||
|
||||
StringBuilder errors = new StringBuilder();
|
||||
TableBuilder tableBuilder = new TableBuilder(" ");
|
||||
TableBuilder.SharedTable sharedTable = new TableBuilder.SharedTable(" ");
|
||||
|
||||
if (printPort)
|
||||
Map<String, Float> ownerships = null;
|
||||
boolean hasEffectiveOwns = false;
|
||||
try
|
||||
{
|
||||
Map<String, Float> ownerships = null;
|
||||
boolean hasEffectiveOwns = false;
|
||||
try
|
||||
{
|
||||
ownerships = probe.effectiveOwnershipWithPort(keyspace);
|
||||
hasEffectiveOwns = true;
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
ownerships = probe.getOwnershipWithPort();
|
||||
errors.append("Note: ").append(e.getMessage()).append("%n");
|
||||
}
|
||||
catch (IllegalArgumentException ex)
|
||||
{
|
||||
System.out.printf("%nError: %s%n", ex.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
SortedMap<String, SetHostStatWithPort> dcs = NodeTool.getOwnershipByDcWithPort(probe, resolveIp, tokensToEndpoints, ownerships);
|
||||
|
||||
// More tokens than nodes (aka vnodes)?
|
||||
if (dcs.size() < tokensToEndpoints.size())
|
||||
isTokenPerNode = false;
|
||||
|
||||
// Datacenters
|
||||
for (Map.Entry<String, SetHostStatWithPort> dc : dcs.entrySet())
|
||||
{
|
||||
String dcHeader = String.format("Datacenter: %s%n", dc.getKey());
|
||||
System.out.print(dcHeader);
|
||||
for (int i = 0; i < (dcHeader.length() - 1); i++) System.out.print('=');
|
||||
System.out.println();
|
||||
|
||||
// Legend
|
||||
System.out.println("Status=Up/Down");
|
||||
System.out.println("|/ State=Normal/Leaving/Joining/Moving");
|
||||
|
||||
addNodesHeader(hasEffectiveOwns, tableBuilder);
|
||||
|
||||
ArrayListMultimap<InetAddressAndPort, HostStatWithPort> hostToTokens = ArrayListMultimap.create();
|
||||
for (HostStatWithPort stat : dc.getValue())
|
||||
hostToTokens.put(stat.endpoint, stat);
|
||||
|
||||
for (InetAddressAndPort endpoint : hostToTokens.keySet())
|
||||
{
|
||||
Float owns = ownerships.get(endpoint.toString());
|
||||
List<HostStatWithPort> tokens = hostToTokens.get(endpoint);
|
||||
addNodeWithPort(endpoint.toString(), owns, tokens, hasEffectiveOwns, tableBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
tableBuilder.printTo(System.out);
|
||||
System.out.printf("%n" + errors);
|
||||
ownerships = probe.effectiveOwnershipWithPort(keyspace);
|
||||
hasEffectiveOwns = true;
|
||||
}
|
||||
else
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
Map<InetAddress, Float> ownerships = null;
|
||||
boolean hasEffectiveOwns = false;
|
||||
try
|
||||
{
|
||||
ownerships = probe.effectiveOwnership(keyspace);
|
||||
hasEffectiveOwns = true;
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
ownerships = probe.getOwnership();
|
||||
errors.append("Note: ").append(e.getMessage()).append("%n");
|
||||
}
|
||||
catch (IllegalArgumentException ex)
|
||||
{
|
||||
System.out.printf("%nError: %s%n", ex.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
SortedMap<String, SetHostStat> dcs = NodeTool.getOwnershipByDc(probe, resolveIp, tokensToEndpoints, ownerships);
|
||||
|
||||
// More tokens than nodes (aka vnodes)?
|
||||
if (dcs.values().size() < tokensToEndpoints.keySet().size())
|
||||
isTokenPerNode = false;
|
||||
|
||||
// Datacenters
|
||||
for (Map.Entry<String, SetHostStat> dc : dcs.entrySet())
|
||||
{
|
||||
String dcHeader = String.format("Datacenter: %s%n", dc.getKey());
|
||||
System.out.print(dcHeader);
|
||||
for (int i = 0; i < (dcHeader.length() - 1); i++) System.out.print('=');
|
||||
System.out.println();
|
||||
|
||||
// Legend
|
||||
System.out.println("Status=Up/Down");
|
||||
System.out.println("|/ State=Normal/Leaving/Joining/Moving");
|
||||
|
||||
addNodesHeader(hasEffectiveOwns, tableBuilder);
|
||||
|
||||
ArrayListMultimap<InetAddress, HostStat> hostToTokens = ArrayListMultimap.create();
|
||||
for (HostStat stat : dc.getValue())
|
||||
hostToTokens.put(stat.endpoint, stat);
|
||||
|
||||
for (InetAddress endpoint : hostToTokens.keySet())
|
||||
{
|
||||
Float owns = ownerships.get(endpoint);
|
||||
List<HostStat> tokens = hostToTokens.get(endpoint);
|
||||
addNode(endpoint.getHostAddress(), owns, tokens, hasEffectiveOwns, tableBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
tableBuilder.printTo(System.out);
|
||||
System.out.printf("%n" + errors);
|
||||
ownerships = probe.getOwnershipWithPort();
|
||||
errors.append("Note: ").append(e.getMessage()).append("%n");
|
||||
}
|
||||
catch (IllegalArgumentException ex)
|
||||
{
|
||||
System.out.printf("%nError: %s%n", ex.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
SortedMap<String, SetHostStatWithPort> dcs = NodeTool.getOwnershipByDcWithPort(probe, resolveIp, tokensToEndpoints, ownerships);
|
||||
|
||||
// More tokens than nodes (aka vnodes)?
|
||||
if (dcs.size() < tokensToEndpoints.size())
|
||||
isTokenPerNode = false;
|
||||
|
||||
// Datacenters
|
||||
for (Map.Entry<String, SetHostStatWithPort> dc : dcs.entrySet())
|
||||
{
|
||||
TableBuilder tableBuilder = sharedTable.next();
|
||||
addNodesHeader(hasEffectiveOwns, tableBuilder);
|
||||
|
||||
ArrayListMultimap<String, HostStatWithPort> hostToTokens = ArrayListMultimap.create();
|
||||
for (HostStatWithPort stat : dc.getValue())
|
||||
hostToTokens.put(stat.ipOrDns(printPort), stat);
|
||||
|
||||
for (String endpoint : hostToTokens.keySet())
|
||||
{
|
||||
Float owns = ownerships.get(endpoint);
|
||||
List<HostStatWithPort> tokens = hostToTokens.get(endpoint);
|
||||
addNode(endpoint, owns, tokens.get(0).ipOrDns(printPort), tokens.get(0).token, tokens.size(),
|
||||
hasEffectiveOwns, tableBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<TableBuilder> results = sharedTable.complete().iterator();
|
||||
boolean first = true;
|
||||
for (Map.Entry<String, SetHostStatWithPort> dc : dcs.entrySet())
|
||||
{
|
||||
if (!first) {
|
||||
System.out.println();
|
||||
}
|
||||
first = false;
|
||||
String dcHeader = String.format("Datacenter: %s%n", dc.getKey());
|
||||
System.out.print(dcHeader);
|
||||
for (int i = 0; i < (dcHeader.length() - 1); i++) System.out.print('=');
|
||||
System.out.println();
|
||||
|
||||
// Legend
|
||||
System.out.println("Status=Up/Down");
|
||||
System.out.println("|/ State=Normal/Leaving/Joining/Moving");
|
||||
TableBuilder dcTable = results.next();
|
||||
dcTable.printTo(System.out);
|
||||
}
|
||||
|
||||
System.out.printf("%n" + errors);
|
||||
}
|
||||
|
||||
private void addNodesHeader(boolean hasEffectiveOwns, TableBuilder tableBuilder)
|
||||
|
|
@ -226,15 +181,4 @@ public class Status extends NodeToolCmd
|
|||
}
|
||||
}
|
||||
|
||||
private void addNode(String endpoint, Float owns, List<HostStat> tokens, boolean hasEffectiveOwns,
|
||||
TableBuilder tableBuilder)
|
||||
{
|
||||
addNode(endpoint, owns, tokens.get(0).ipOrDns(), tokens.get(0).token, tokens.size(), hasEffectiveOwns, tableBuilder);
|
||||
}
|
||||
|
||||
private void addNodeWithPort(String endpoint, Float owns, List<HostStatWithPort> tokens, boolean hasEffectiveOwns,
|
||||
TableBuilder tableBuilder)
|
||||
{
|
||||
addNode(endpoint, owns, tokens.get(0).ipOrDns(), tokens.get(0).token, tokens.size(), hasEffectiveOwns, tableBuilder);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,11 @@ package org.apache.cassandra.tools.nodetool.formatter;
|
|||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
|
|
@ -62,6 +65,13 @@ public class TableBuilder
|
|||
this.columnDelimiter = columnDelimiter;
|
||||
}
|
||||
|
||||
private TableBuilder(TableBuilder base, int[] maximumColumnWidth)
|
||||
{
|
||||
this(base.columnDelimiter);
|
||||
this.maximumColumnWidth = maximumColumnWidth;
|
||||
this.rows.addAll(base.rows);
|
||||
}
|
||||
|
||||
public void add(@Nonnull String... row)
|
||||
{
|
||||
Objects.requireNonNull(row);
|
||||
|
|
@ -105,4 +115,56 @@ public class TableBuilder
|
|||
out.println();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Share max offsets across multiple TableBuilders
|
||||
*/
|
||||
public static class SharedTable {
|
||||
private List<TableBuilder> tables = new ArrayList<>();
|
||||
private final String columnDelimiter;
|
||||
|
||||
public SharedTable()
|
||||
{
|
||||
this(' ');
|
||||
}
|
||||
|
||||
public SharedTable(char columnDelimiter)
|
||||
{
|
||||
this(String.valueOf(columnDelimiter));
|
||||
}
|
||||
|
||||
public SharedTable(String columnDelimiter)
|
||||
{
|
||||
this.columnDelimiter = columnDelimiter;
|
||||
}
|
||||
|
||||
public TableBuilder next()
|
||||
{
|
||||
TableBuilder next = new TableBuilder(columnDelimiter);
|
||||
tables.add(next);
|
||||
return next;
|
||||
}
|
||||
|
||||
public List<TableBuilder> complete()
|
||||
{
|
||||
if (tables.size() == 0)
|
||||
return Collections.emptyList();
|
||||
|
||||
final int columns = tables.stream()
|
||||
.max(Comparator.comparing(tb -> tb.maximumColumnWidth.length))
|
||||
.get().maximumColumnWidth.length;
|
||||
|
||||
final int[] maximumColumnWidth = new int[columns];
|
||||
for (TableBuilder tb : tables)
|
||||
{
|
||||
for (int i = 0; i < tb.maximumColumnWidth.length; i++)
|
||||
{
|
||||
maximumColumnWidth[i] = Math.max(tb.maximumColumnWidth[i], maximumColumnWidth[i]);
|
||||
}
|
||||
}
|
||||
return tables.stream()
|
||||
.map(tb -> new TableBuilder(tb, maximumColumnWidth))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue