Add nodetool getreplicas

nodetool getendpoints is deprecated. Also, all StorageServiceMBean.getNaturalEndpoints* methods are
deprecated and they call their replica counterparts. The deprecated methods are also not used directly anywhere
in the code (nor tests).

patch by Stefan Miklosovic; reviewed by Brandon Williams for CASSANDRA-17665
This commit is contained in:
Stefan Miklosovic 2022-05-27 12:24:42 +02:00
parent e805b8aa32
commit ca42cfe68d
No known key found for this signature in database
GPG Key ID: 32F35CB2F546D93E
12 changed files with 179 additions and 76 deletions

View File

@ -1,4 +1,5 @@
7.0
* Add nodetool getreplicas (CASSANDRA-17665)
* Implementation of CEP-49: Hardware-accelerated compression (CASSANDRA-20975)
* Avoid using ObjectUtils.getFirstNonNull in Schema (CASSANDRA-21394)
* Allow nodetool garbagecollect to take a user defined list of SSTables (CASSANDRA-16767)

View File

@ -3403,6 +3403,11 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
*/
@Deprecated(since = "4.0")
public List<InetAddress> getNaturalEndpoints(String keyspaceName, String cf, String key)
{
return getNaturalReplicas(keyspaceName, cf, key);
}
public List<InetAddress> getNaturalReplicas(String keyspaceName, String cf, String key)
{
EndpointsForToken replicas = getNaturalReplicasForToken(keyspaceName, cf, key);
List<InetAddress> inetList = new ArrayList<>(replicas.size());
@ -3410,11 +3415,16 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
return inetList;
}
public List<String> getNaturalEndpointsWithPort(String keyspaceName, String cf, String key)
public List<String> getNaturalReplicasWithPort(String keyspaceName, String cf, String key)
{
return Replicas.stringify(getNaturalReplicasForToken(keyspaceName, cf, key), true);
}
public List<String> getNaturalEndpointsWithPort(String keyspaceName, String cf, String key)
{
return getNaturalReplicasWithPort(keyspaceName, cf, key);
}
/** @deprecated See CASSANDRA-7544 */
@Deprecated(since = "4.0")
public List<InetAddress> getNaturalEndpoints(String keyspaceName, ByteBuffer key)

View File

@ -262,12 +262,28 @@ public interface StorageServiceMBean extends NotificationEmitter
* @param key - key for which we need to find the endpoint return value -
* the endpoint responsible for this key
* @deprecated See CASSANDRA-7544
* @link getNaturalReplicas
* @link getNaturalReplicasWithPort
*/
@Deprecated(since = "4.0") public List<InetAddress> getNaturalEndpoints(String keyspaceName, String cf, String key);
public List<String> getNaturalEndpointsWithPort(String keyspaceName, String cf, String key);
/** @deprecated See CASSANDRA-17665 */
@Deprecated(since = "7.0") public List<String> getNaturalEndpointsWithPort(String keyspaceName, String cf, String key);
/** @deprecated See CASSANDRA-7544 */
@Deprecated(since = "4.0") public List<InetAddress> getNaturalEndpoints(String keyspaceName, ByteBuffer key);
public List<String> getNaturalEndpointsWithPort(String keysapceName, ByteBuffer key);
/** @deprecated See CASSANDRA-17665 */
@Deprecated(since = "7.0") public List<String> getNaturalEndpointsWithPort(String keysapceName, ByteBuffer key);
/**
* This method returns the N replicas that are responsible for storing the
* specified key i.e for replication.
*
* @param keyspaceName keyspace name
* @param cf Column family name
* @param key - key for which we need to find the replica return value -
* the replica responsible for this key
*/
public List<InetAddress> getNaturalReplicas(String keyspaceName, String cf, String key);
public List<String> getNaturalReplicasWithPort(String keyspaceName, String cf, String key);
/**
* @deprecated use {@link #takeSnapshot(String tag, Map options, String... entities)} instead. See CASSANDRA-10907

View File

@ -1200,14 +1200,14 @@ public class NodeProbe implements AutoCloseable
ssProxy.setHintedHandoffThrottleInKB(throttleInKB);
}
public List<String> getEndpointsWithPort(String keyspace, String cf, String key)
public List<String> getReplicasWithPort(String keyspace, String cf, String key)
{
return ssProxy.getNaturalEndpointsWithPort(keyspace, cf, key);
return ssProxy.getNaturalReplicasWithPort(keyspace, cf, key);
}
public List<InetAddress> getEndpoints(String keyspace, String cf, String key)
public List<InetAddress> getReplicas(String keyspace, String cf, String key)
{
return ssProxy.getNaturalEndpoints(keyspace, cf, key);
return ssProxy.getNaturalReplicas(keyspace, cf, key);
}
public List<String> getSSTables(String keyspace, String cf, String key, boolean hexFormat)

View File

@ -17,62 +17,10 @@
*/
package org.apache.cassandra.tools.nodetool;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import org.apache.cassandra.tools.NodeProbe;
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Parameters;
import static com.google.common.base.Preconditions.checkArgument;
import static org.apache.cassandra.tools.nodetool.CommandUtils.concatArgs;
@Command(name = "getendpoints", description = "Print the end points that owns the key")
public class GetEndpoints extends AbstractCommand
@Deprecated(since = "7.0") // this is alias to getreplicas
@Command(name = "getendpoints", description = "Print the end points that owns the key, deprecated, use getreplicas instead")
public class GetEndpoints extends GetReplicas
{
@CassandraUsage(usage = "<keyspace> <table> <key>", description = "The keyspace, the table, and the partition key for which we need to find the endpoint")
private List<String> args = new ArrayList<>();
@Parameters(index = "0", arity = "0..1", description = "The keyspace for which we need to find the endpoint")
private String keyspace;
@Parameters(index = "1", arity = "0..1", description = "The table for which we need to find the endpoint")
private String table;
@Parameters(index = "2", arity = "0..1", description = "The partition key for which we need to find the endpoint")
private String key;
@Mixin
private PrintPortMixin printPortMixin = new PrintPortMixin();
@Override
public void execute(NodeProbe probe)
{
args = concatArgs(keyspace, table, key);
checkArgument(args.size() == 3, "getendpoints requires keyspace, table and partition key arguments");
String ks = args.get(0);
String table = args.get(1);
String key = args.get(2);
if (printPortMixin.printPort)
{
for (String endpoint : probe.getEndpointsWithPort(ks, table, key))
{
probe.output().out.println(endpoint);
}
}
else
{
List<InetAddress> endpoints = probe.getEndpoints(ks, table, key);
for (InetAddress endpoint : endpoints)
{
probe.output().out.println(endpoint.getHostAddress());
}
}
}
}

View File

@ -0,0 +1,79 @@
/*
* 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;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import org.apache.cassandra.tools.NodeProbe;
import org.apache.cassandra.tools.nodetool.layout.CassandraUsage;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Parameters;
import static com.google.common.base.Preconditions.checkArgument;
import static org.apache.cassandra.tools.nodetool.CommandUtils.concatArgs;
@Command(name = "getreplicas", description = "Print the replicas that own the key")
public class GetReplicas extends AbstractCommand
{
@CassandraUsage(usage = "<keyspace> <table> <key>", description = "The keyspace, the table, and the partition key for which we need to find the replica")
private List<String> args = new ArrayList<>();
@Parameters(index = "0", arity = "0..1", description = "The keyspace for which we need to find the replica")
private String keyspace;
@Parameters(index = "1", arity = "0..1", description = "The table for which we need to find the replica")
private String table;
@Parameters(index = "2", arity = "0..1", description = "The partition key for which we need to find the replica")
private String key;
@Mixin
private PrintPortMixin printPortMixin = new PrintPortMixin();
@Override
public void execute(NodeProbe probe)
{
args = concatArgs(keyspace, table, key);
checkArgument(args.size() == 3, "requires keyspace, table and partition key arguments");
String ks = args.get(0);
String table = args.get(1);
String key = args.get(2);
if (printPortMixin.printPort)
{
for (String replica : probe.getReplicasWithPort(ks, table, key))
{
probe.output().out.println(replica);
}
}
else
{
List<InetAddress> replicas = probe.getReplicas(ks, table, key);
for (InetAddress replica : replicas)
{
probe.output().out.println(replica.getHostAddress());
}
}
}
}

View File

@ -120,6 +120,7 @@ import static org.apache.cassandra.tools.nodetool.Help.printTopCommandUsage;
GetInterDCStreamThroughput.class,
GetLoggingLevels.class,
GetMaxHintWindow.class,
GetReplicas.class,
GetSSTables.class,
GetSeeds.class,
GetSnapshotThrottle.class,

View File

@ -81,9 +81,9 @@ public class GetEndpointsTest extends TestBaseImpl
for (IInvokableInstance i : cluster)
{
i.runOnInstance(() -> {
List<String> endpoints = StorageService.instance.getNaturalEndpointsWithPort("system_cluster_metadata", "distributed_metadata_log", "1");
assertEquals(endpoints.toString(), 3, endpoints.size());
assertEquals(Replicas.stringify(ClusterMetadata.current().fullCMSMembersAsReplicas(), true), endpoints);
List<String> replicas = StorageService.instance.getNaturalReplicasWithPort("system_cluster_metadata", "distributed_metadata_log", "1");
assertEquals(replicas.toString(), 3, replicas.size());
assertEquals(Replicas.stringify(ClusterMetadata.current().fullCMSMembersAsReplicas(), true), replicas);
});
}

View File

@ -19,6 +19,7 @@
package org.apache.cassandra.distributed.test;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@ -32,6 +33,8 @@ import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.distributed.Cluster;
import org.apache.cassandra.gms.FailureDetector;
import org.apache.cassandra.gms.Gossiper;
import org.apache.cassandra.locator.EndpointsForToken;
import org.apache.cassandra.locator.Replicas;
import org.apache.cassandra.net.MessagingService;
import org.apache.cassandra.schema.SchemaConstants;
import org.apache.cassandra.schema.SystemDistributedKeyspace;
@ -78,16 +81,22 @@ public class GossipSettlesTest extends TestBaseImpl
Assert.assertEquals(addPortToValues(ss.getHostIdToEndpoint()), ss.getHostIdToEndpointWithPort());
Assert.assertEquals(addPortToKeys(ss.getLoadMap()), ss.getLoadMapWithPort());
Assert.assertEquals(addPortToList(ss.getLiveNodes()), ss.getLiveNodesWithPort());
List<String> naturalEndpointsAddedPort = ss.getNaturalEndpoints(SchemaConstants.DISTRIBUTED_KEYSPACE_NAME,
List<String> naturalReplicasAddedPort = ss.getNaturalReplicas(SchemaConstants.DISTRIBUTED_KEYSPACE_NAME,
SystemDistributedKeyspace.VIEW_BUILD_STATUS, "dummy").stream()
.map(e -> addStoragePortToIP(e.getHostAddress())).collect(Collectors.toList());
Assert.assertEquals(naturalEndpointsAddedPort,
ss.getNaturalEndpointsWithPort(SchemaConstants.DISTRIBUTED_KEYSPACE_NAME,
SystemDistributedKeyspace.VIEW_BUILD_STATUS, "dummy"));
naturalEndpointsAddedPort = ss.getNaturalEndpoints(SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, ByteBufferUtil.EMPTY_BYTE_BUFFER).stream()
.map(e -> addStoragePortToIP(e.getHostAddress())).collect(Collectors.toList());
Assert.assertEquals(naturalEndpointsAddedPort,
ss.getNaturalEndpointsWithPort(SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, ByteBufferUtil.EMPTY_BYTE_BUFFER));
Assert.assertEquals(naturalReplicasAddedPort,
ss.getNaturalReplicasWithPort(SchemaConstants.DISTRIBUTED_KEYSPACE_NAME,
SystemDistributedKeyspace.VIEW_BUILD_STATUS, "dummy"));
EndpointsForToken replicas = ss.getNaturalReplicasForToken(SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, ByteBufferUtil.EMPTY_BYTE_BUFFER);
List<InetAddress> inetList = new ArrayList<>(replicas.size());
replicas.forEach(r -> inetList.add(r.endpoint().getAddress()));
naturalReplicasAddedPort = inetList.stream().map(e -> addStoragePortToIP(e.getHostAddress())).collect(Collectors.toList());
List<String> replicas2 = Replicas.stringify(ss.getNaturalReplicasForToken(SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, ByteBufferUtil.EMPTY_BYTE_BUFFER), true);
Assert.assertEquals(naturalReplicasAddedPort, replicas2);
// Difference in key type... convert to String and add the port to the older format

View File

@ -1,5 +1,6 @@
NAME
nodetool getendpoints - Print the end points that owns the key
nodetool getendpoints - Print the end points that owns the key,
deprecated, use getreplicas instead
SYNOPSIS
nodetool [(-h <host> | --host <host>)] [(-p <port> | --port <port>)]
@ -34,4 +35,4 @@ OPTIONS
<keyspace> <table> <key>
The keyspace, the table, and the partition key for which we need to
find the endpoint
find the replica

View File

@ -0,0 +1,37 @@
NAME
nodetool getreplicas - Print the replicas that own the key
SYNOPSIS
nodetool [(-h <host> | --host <host>)] [(-p <port> | --port <port>)]
[(-pw <password> | --password <password>)]
[(-pwf <passwordFilePath> | --password-file <passwordFilePath>)]
[(-u <username> | --username <username>)] getreplicas
[(-pp | --print-port)] [--] <keyspace> <table> <key>
OPTIONS
-h <host>, --host <host>
Node hostname or ip address
-p <port>, --port <port>
Remote jmx agent port number
-pp, --print-port
Operate in 4.0 mode with hosts disambiguated by port number
-pw <password>, --password <password>
Remote jmx agent password
-pwf <passwordFilePath>, --password-file <passwordFilePath>
Path to the JMX password file
-u <username>, --username <username>
Remote jmx agent username
--
This option can be used to separate command-line options from the
list of argument, (useful when arguments might be mistaken for
command-line options
<keyspace> <table> <key>
The keyspace, the table, and the partition key for which we need to
find the replica

View File

@ -64,12 +64,13 @@ The most commonly used nodetool commands are:
getconcurrentcompactors Get the number of concurrent compactors in the system.
getconcurrentviewbuilders Get the number of concurrent view builders in the system
getdefaultrf Gets default keyspace replication factor.
getendpoints Print the end points that owns the key
getendpoints Print the end points that owns the key, deprecated, use getreplicas instead
getfullquerylog Print configuration of fql if enabled, otherwise the configuration reflected in cassandra.yaml
getguardrailsconfig Print runtime configuration of guardrails.
getinterdcstreamthroughput Print the throughput cap for inter-datacenter streaming and entire SSTable inter-datacenter streaming in the systemin rounded megabits. For precise number, please, use option -d
getlogginglevels Get the runtime logging levels
getmaxhintwindow Print the max hint window in ms
getreplicas Print the replicas that own the key
getseeds Get the currently in use seed node IP list excluding the node IP
getsnapshotthrottle Print the snapshot_links_per_second throttle for snapshot/clearsnapshot
getsstables Print the sstable filenames that own the key