2015-06-04 12:35:57 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright 2015 Cloudius Systems
|
|
|
|
*
|
|
|
|
* Modified by Cloudius Systems
|
|
|
|
*/
|
|
|
|
package org.apache.cassandra.db;
|
|
|
|
|
2016-08-17 10:30:04 +02:00
|
|
|
import static java.lang.String.valueOf;
|
2016-10-11 14:05:05 +02:00
|
|
|
import static java.util.Arrays.asList;
|
2016-11-01 10:44:17 +01:00
|
|
|
import static java.util.stream.Collectors.toMap;
|
2016-08-17 10:30:04 +02:00
|
|
|
import static javax.json.Json.createObjectBuilder;
|
|
|
|
|
|
|
|
import java.io.StringReader;
|
2020-12-11 16:17:57 +01:00
|
|
|
import java.io.OutputStream;
|
2016-11-01 10:44:17 +01:00
|
|
|
import java.util.Collections;
|
2020-09-01 15:45:45 +02:00
|
|
|
import java.util.EnumSet;
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
import java.util.HashMap;
|
2016-08-17 10:30:04 +02:00
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Set;
|
|
|
|
import java.util.concurrent.ExecutionException;
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
import java.util.concurrent.ExecutorService;
|
|
|
|
import java.util.concurrent.Executors;
|
|
|
|
import java.util.concurrent.Future;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
2016-10-11 14:05:05 +02:00
|
|
|
import java.util.logging.Logger;
|
2015-06-04 12:35:57 +02:00
|
|
|
|
2016-11-01 10:44:17 +01:00
|
|
|
import javax.json.Json;
|
2015-06-04 12:35:57 +02:00
|
|
|
import javax.json.JsonArray;
|
|
|
|
import javax.json.JsonObject;
|
2016-08-17 10:30:04 +02:00
|
|
|
import javax.json.JsonObjectBuilder;
|
2016-11-01 10:44:17 +01:00
|
|
|
import javax.json.JsonReader;
|
2016-08-17 10:30:04 +02:00
|
|
|
import javax.management.MBeanServer;
|
2016-10-11 14:05:05 +02:00
|
|
|
import javax.management.MalformedObjectNameException;
|
2016-08-17 10:30:04 +02:00
|
|
|
import javax.management.ObjectName;
|
2020-09-01 15:45:45 +02:00
|
|
|
import javax.management.OperationsException;
|
2015-07-30 11:01:05 +02:00
|
|
|
import javax.management.openmbean.CompositeData;
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
import javax.management.openmbean.CompositeDataSupport;
|
|
|
|
import javax.management.openmbean.CompositeType;
|
2015-07-30 11:01:05 +02:00
|
|
|
import javax.management.openmbean.OpenDataException;
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
import javax.management.openmbean.OpenType;
|
|
|
|
import javax.management.openmbean.SimpleType;
|
|
|
|
import javax.management.openmbean.TabularDataSupport;
|
|
|
|
import javax.management.openmbean.TabularType;
|
2015-10-28 10:25:37 +01:00
|
|
|
import javax.ws.rs.core.MultivaluedHashMap;
|
2015-06-21 08:46:29 +02:00
|
|
|
import javax.ws.rs.core.MultivaluedMap;
|
2015-06-04 12:35:57 +02:00
|
|
|
|
2016-10-11 14:05:05 +02:00
|
|
|
import org.apache.cassandra.metrics.TableMetrics;
|
2015-06-24 10:15:26 +02:00
|
|
|
|
2015-12-17 08:26:19 +01:00
|
|
|
import com.scylladb.jmx.api.APIClient;
|
2016-10-11 14:05:05 +02:00
|
|
|
import com.scylladb.jmx.metrics.MetricsMBean;
|
2020-09-01 15:45:45 +02:00
|
|
|
import com.scylladb.jmx.metrics.RegistrationChecker;
|
|
|
|
import com.scylladb.jmx.metrics.RegistrationMode;
|
2018-05-12 18:35:18 +02:00
|
|
|
import com.sun.jmx.mbeanserver.JmxMBeanServer;
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
import com.google.common.base.Throwables;
|
2015-06-04 12:35:57 +02:00
|
|
|
|
2016-10-11 14:05:05 +02:00
|
|
|
public class ColumnFamilyStore extends MetricsMBean implements ColumnFamilyStoreMBean {
|
|
|
|
private static final Logger logger = Logger.getLogger(ColumnFamilyStore.class.getName());
|
2016-08-17 10:30:04 +02:00
|
|
|
@SuppressWarnings("unused")
|
2016-10-11 14:05:05 +02:00
|
|
|
private final String type;
|
|
|
|
private final String keyspace;
|
|
|
|
private final String name;
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
private static final String[] COUNTER_NAMES = new String[]{"raw", "count", "error", "string"};
|
|
|
|
private static final String[] COUNTER_DESCS = new String[]
|
|
|
|
{ "partition key in raw hex bytes", // Table name and comments match Cassandra, we will use the partition key
|
|
|
|
"value of this partition for given sampler",
|
|
|
|
"value is within the error bounds plus or minus of this",
|
|
|
|
"the partition key turned into a human readable format" };
|
|
|
|
private static final CompositeType COUNTER_COMPOSITE_TYPE;
|
|
|
|
private static final TabularType COUNTER_TYPE;
|
|
|
|
|
|
|
|
private static final String[] SAMPLER_NAMES = new String[]{"cardinality", "partitions"};
|
|
|
|
private static final String[] SAMPLER_DESCS = new String[]
|
|
|
|
{ "cardinality of partitions",
|
|
|
|
"list of counter results" };
|
|
|
|
|
|
|
|
private static final String SAMPLING_RESULTS_NAME = "SAMPLING_RESULTS";
|
|
|
|
private static final CompositeType SAMPLING_RESULT;
|
|
|
|
|
|
|
|
public static final String SNAPSHOT_TRUNCATE_PREFIX = "truncated";
|
|
|
|
public static final String SNAPSHOT_DROP_PREFIX = "dropped";
|
|
|
|
private JsonObject tableSamplerResult = null;
|
|
|
|
|
|
|
|
private Future<JsonObject> futureTableSamperResult = null;
|
|
|
|
private ExecutorService service = null;
|
|
|
|
|
|
|
|
static
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
OpenType<?>[] counterTypes = new OpenType[] { SimpleType.STRING, SimpleType.LONG, SimpleType.LONG, SimpleType.STRING };
|
|
|
|
COUNTER_COMPOSITE_TYPE = new CompositeType(SAMPLING_RESULTS_NAME, SAMPLING_RESULTS_NAME, COUNTER_NAMES, COUNTER_DESCS, counterTypes);
|
|
|
|
COUNTER_TYPE = new TabularType(SAMPLING_RESULTS_NAME, SAMPLING_RESULTS_NAME, COUNTER_COMPOSITE_TYPE, COUNTER_NAMES);
|
|
|
|
|
|
|
|
OpenType<?>[] samplerTypes = new OpenType[] { SimpleType.LONG, COUNTER_TYPE };
|
|
|
|
SAMPLING_RESULT = new CompositeType(SAMPLING_RESULTS_NAME, SAMPLING_RESULTS_NAME, SAMPLER_NAMES, SAMPLER_DESCS, samplerTypes);
|
|
|
|
} catch (OpenDataException e)
|
|
|
|
{
|
|
|
|
throw Throwables.propagate(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected synchronized void startTableSampling(MultivaluedMap<String, String> queryParams) {
|
|
|
|
if (futureTableSamperResult != null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
futureTableSamperResult = service.submit(() -> {
|
|
|
|
tableSamplerResult = client.getJsonObj("column_family/toppartitions/" + getCFName(), queryParams);
|
|
|
|
return null;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait until the action is completed
|
|
|
|
* It is safe to call this method multiple times
|
|
|
|
*/
|
|
|
|
public synchronized void waitUntilSamplingCompleted() {
|
|
|
|
try {
|
|
|
|
if (futureTableSamperResult != null) {
|
|
|
|
futureTableSamperResult.get();
|
|
|
|
futureTableSamperResult = null;
|
|
|
|
}
|
|
|
|
} catch (InterruptedException | ExecutionException e) {
|
|
|
|
futureTableSamperResult = null;
|
2019-03-11 09:29:41 +01:00
|
|
|
throw new RuntimeException("Failed getting table statistics", e);
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-04 12:35:57 +02:00
|
|
|
|
2016-10-11 14:05:05 +02:00
|
|
|
public static final Set<String> TYPE_NAMES = new HashSet<>(asList("ColumnFamilies", "IndexTables", "Tables"));
|
2015-06-04 12:35:57 +02:00
|
|
|
|
|
|
|
public void log(String str) {
|
2015-12-30 07:47:32 +01:00
|
|
|
logger.finest(str);
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
2016-10-11 14:05:05 +02:00
|
|
|
public ColumnFamilyStore(APIClient client, String type, String keyspace, String name) {
|
|
|
|
super(client,
|
|
|
|
new TableMetrics(keyspace, name, false /* hardcoded for now */));
|
2015-06-21 08:46:29 +02:00
|
|
|
this.type = type;
|
|
|
|
this.keyspace = keyspace;
|
|
|
|
this.name = name;
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
service = Executors.newSingleThreadExecutor();
|
2016-10-11 14:05:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public ColumnFamilyStore(APIClient client, ObjectName name) {
|
|
|
|
this(client, name.getKeyProperty("type"), name.getKeyProperty("keyspace"), name.getKeyProperty("columnfamily"));
|
2015-06-24 10:15:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** true if this CFS contains secondary index data */
|
|
|
|
/*
|
|
|
|
* It is hard coded to false until secondary index is supported
|
|
|
|
*/
|
|
|
|
public boolean isIndex() {
|
|
|
|
return false;
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
2015-06-21 08:46:29 +02:00
|
|
|
/**
|
|
|
|
* Get the column family name in the API format
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public String getCFName() {
|
|
|
|
return keyspace + ":" + name;
|
|
|
|
}
|
|
|
|
|
2016-10-11 14:05:05 +02:00
|
|
|
private static ObjectName getName(String type, String keyspace, String name) throws MalformedObjectNameException {
|
|
|
|
return new ObjectName(
|
|
|
|
"org.apache.cassandra.db:type=" + type + ",keyspace=" + keyspace + ",columnfamily=" + name);
|
|
|
|
}
|
|
|
|
|
2020-09-01 15:45:45 +02:00
|
|
|
public static RegistrationChecker createRegistrationChecker() {
|
|
|
|
return new RegistrationChecker() {
|
|
|
|
@Override
|
|
|
|
protected void doCheck(APIClient client, JmxMBeanServer server, EnumSet<RegistrationMode> mode)
|
|
|
|
throws OperationsException {
|
|
|
|
JsonArray mbeans = client.getJsonArray("/column_family/");
|
|
|
|
Set<ObjectName> all = new HashSet<ObjectName>();
|
|
|
|
for (int i = 0; i < mbeans.size(); i++) {
|
|
|
|
JsonObject mbean = mbeans.getJsonObject(i);
|
|
|
|
all.add(getName(mbean.getString("type"), mbean.getString("ks"), mbean.getString("cf")));
|
|
|
|
}
|
|
|
|
checkRegistration(server, all, mode,
|
|
|
|
n -> TYPE_NAMES.contains(n.getKeyProperty("type")), n -> new ColumnFamilyStore(client, n));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2015-06-04 12:35:57 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the name of the column family
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public String getColumnFamilyName() {
|
|
|
|
log(" getColumnFamilyName()");
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* force a major compaction of this column family
|
|
|
|
*/
|
2016-10-11 14:05:05 +02:00
|
|
|
public void forceMajorCompaction() throws ExecutionException, InterruptedException {
|
2015-06-04 12:35:57 +02:00
|
|
|
log(" forceMajorCompaction() throws ExecutionException, InterruptedException");
|
2016-10-11 14:05:05 +02:00
|
|
|
client.post("column_family/major_compaction/" + getCFName());
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the minimum number of sstables in queue before compaction kicks off
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public int getMinimumCompactionThreshold() {
|
|
|
|
log(" getMinimumCompactionThreshold()");
|
2016-10-11 14:05:05 +02:00
|
|
|
return client.getIntValue("column_family/minimum_compaction/" + getCFName());
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the minimum number of sstables in queue before compaction kicks off
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public void setMinimumCompactionThreshold(int threshold) {
|
|
|
|
log(" setMinimumCompactionThreshold(int threshold)");
|
2015-10-28 10:25:37 +01:00
|
|
|
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<String, String>();
|
2015-06-21 08:46:29 +02:00
|
|
|
queryParams.add("value", Integer.toString(threshold));
|
2016-10-11 14:05:05 +02:00
|
|
|
client.post("column_family/minimum_compaction/" + getCFName(), queryParams);
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the maximum number of sstables in queue before compaction kicks off
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public int getMaximumCompactionThreshold() {
|
|
|
|
log(" getMaximumCompactionThreshold()");
|
2016-10-11 14:05:05 +02:00
|
|
|
return client.getIntValue("column_family/maximum_compaction/" + getCFName());
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the maximum and maximum number of SSTables in queue before
|
|
|
|
* compaction kicks off
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public void setCompactionThresholds(int minThreshold, int maxThreshold) {
|
|
|
|
log(" setCompactionThresholds(int minThreshold, int maxThreshold)");
|
2015-10-28 10:25:37 +01:00
|
|
|
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<String, String>();
|
2015-06-21 08:46:29 +02:00
|
|
|
queryParams.add("minimum", Integer.toString(minThreshold));
|
|
|
|
queryParams.add("maximum", Integer.toString(maxThreshold));
|
2016-10-11 14:05:05 +02:00
|
|
|
client.post("column_family/compaction" + getCFName(), queryParams);
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the maximum number of sstables in queue before compaction kicks off
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public void setMaximumCompactionThreshold(int threshold) {
|
|
|
|
log(" setMaximumCompactionThreshold(int threshold)");
|
2015-10-28 10:25:37 +01:00
|
|
|
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<String, String>();
|
2015-06-21 08:46:29 +02:00
|
|
|
queryParams.add("value", Integer.toString(threshold));
|
2016-10-11 14:05:05 +02:00
|
|
|
client.post("column_family/maximum_compaction/" + getCFName(), queryParams);
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the compaction strategy by class name
|
2015-06-21 08:46:29 +02:00
|
|
|
*
|
2015-06-04 12:35:57 +02:00
|
|
|
* @param className
|
|
|
|
* the name of the compaction strategy class
|
|
|
|
*/
|
|
|
|
public void setCompactionStrategyClass(String className) {
|
|
|
|
log(" setCompactionStrategyClass(String className)");
|
2015-10-28 10:25:37 +01:00
|
|
|
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<String, String>();
|
2015-06-21 08:46:29 +02:00
|
|
|
queryParams.add("class_name", className);
|
2016-10-11 14:05:05 +02:00
|
|
|
client.post("column_family/compaction_strategy/" + getCFName(), queryParams);
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the compaction strategy class name
|
|
|
|
*/
|
|
|
|
public String getCompactionStrategyClass() {
|
|
|
|
log(" getCompactionStrategyClass()");
|
2016-10-11 14:05:05 +02:00
|
|
|
return client.getStringValue("column_family/compaction_strategy/" + getCFName());
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the compression parameters
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public Map<String, String> getCompressionParameters() {
|
|
|
|
log(" getCompressionParameters()");
|
2016-10-11 14:05:05 +02:00
|
|
|
return client.getMapStrValue("column_family/compression_parameters/" + getCFName());
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the compression parameters
|
2015-06-21 08:46:29 +02:00
|
|
|
*
|
2015-06-04 12:35:57 +02:00
|
|
|
* @param opts
|
|
|
|
* map of string names to values
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public void setCompressionParameters(Map<String, String> opts) {
|
|
|
|
log(" setCompressionParameters(Map<String,String> opts)");
|
2015-10-28 10:25:37 +01:00
|
|
|
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<String, String>();
|
2015-06-21 08:46:29 +02:00
|
|
|
queryParams.add("opts", APIClient.mapToString(opts));
|
2016-10-11 14:05:05 +02:00
|
|
|
client.post("column_family/compression_parameters/" + getCFName(), queryParams);
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set new crc check chance
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public void setCrcCheckChance(double crcCheckChance) {
|
|
|
|
log(" setCrcCheckChance(double crcCheckChance)");
|
2015-10-28 10:25:37 +01:00
|
|
|
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<String, String>();
|
2015-06-21 08:46:29 +02:00
|
|
|
queryParams.add("check_chance", Double.toString(crcCheckChance));
|
2016-10-11 14:05:05 +02:00
|
|
|
client.post("column_family/crc_check_chance/" + getCFName(), queryParams);
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public boolean isAutoCompactionDisabled() {
|
|
|
|
log(" isAutoCompactionDisabled()");
|
2020-05-25 18:58:32 +02:00
|
|
|
return !client.getBooleanValue("column_family/autocompaction/" + getCFName());
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Number of tombstoned cells retreived during the last slicequery */
|
|
|
|
@Deprecated
|
|
|
|
public double getTombstonesPerSlice() {
|
|
|
|
log(" getTombstonesPerSlice()");
|
2016-10-11 14:05:05 +02:00
|
|
|
return client.getDoubleValue("");
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Number of live cells retreived during the last slicequery */
|
|
|
|
@Deprecated
|
|
|
|
public double getLiveCellsPerSlice() {
|
|
|
|
log(" getLiveCellsPerSlice()");
|
2016-10-11 14:05:05 +02:00
|
|
|
return client.getDoubleValue("");
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public long estimateKeys() {
|
|
|
|
log(" estimateKeys()");
|
2016-10-11 14:05:05 +02:00
|
|
|
return client.getLongValue("column_family/estimate_keys/" + getCFName());
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a list of the names of the built column indexes for current store
|
2015-06-21 08:46:29 +02:00
|
|
|
*
|
2015-06-04 12:35:57 +02:00
|
|
|
* @return list of the index names
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public List<String> getBuiltIndexes() {
|
|
|
|
log(" getBuiltIndexes()");
|
2016-10-11 14:05:05 +02:00
|
|
|
return client.getListStrValue("column_family/built_indexes/" + getCFName());
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a list of filenames that contain the given key on this node
|
2015-06-21 08:46:29 +02:00
|
|
|
*
|
2015-06-04 12:35:57 +02:00
|
|
|
* @param key
|
|
|
|
* @return list of filenames containing the key
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public List<String> getSSTablesForKey(String key) {
|
|
|
|
log(" getSSTablesForKey(String key)");
|
2015-10-28 10:25:37 +01:00
|
|
|
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<String, String>();
|
2015-06-21 08:46:29 +02:00
|
|
|
queryParams.add("key", key);
|
2016-10-11 14:05:05 +02:00
|
|
|
return client.getListStrValue("column_family/sstables/by_key/" + getCFName(), queryParams);
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
2019-07-29 09:09:04 +02:00
|
|
|
/**
|
|
|
|
* Returns a list of filenames that contain the given key on this node
|
|
|
|
* @param key
|
|
|
|
* @param hexFormat if key is in hex string format
|
|
|
|
* @return list of filenames containing the key
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public List<String> getSSTablesForKey(String key, boolean hexFormat)
|
|
|
|
{
|
|
|
|
log(" getSSTablesForKey(String key)");
|
|
|
|
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<String, String>();
|
|
|
|
queryParams.add("key", key);
|
|
|
|
if (hexFormat) {
|
|
|
|
queryParams.add("format", "hex");
|
|
|
|
}
|
|
|
|
return client.getListStrValue("column_family/sstables/by_key/" + getCFName(), queryParams);
|
|
|
|
}
|
2015-06-04 12:35:57 +02:00
|
|
|
/**
|
|
|
|
* Scan through Keyspace/ColumnFamily's data directory determine which
|
|
|
|
* SSTables should be loaded and load them
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public void loadNewSSTables() {
|
|
|
|
log(" loadNewSSTables()");
|
2016-10-11 14:05:05 +02:00
|
|
|
client.post("column_family/sstable/" + getCFName());
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the number of SSTables in L0. Always return 0 if Leveled
|
|
|
|
* compaction is not enabled.
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public int getUnleveledSSTables() {
|
|
|
|
log(" getUnleveledSSTables()");
|
2016-10-11 14:05:05 +02:00
|
|
|
return client.getIntValue("column_family/sstables/unleveled/" + getCFName());
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return sstable count for each level. null unless leveled compaction is
|
|
|
|
* used. array index corresponds to level(int[0] is for level 0,
|
|
|
|
* ...).
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public int[] getSSTableCountPerLevel() {
|
|
|
|
log(" getSSTableCountPerLevel()");
|
2016-10-11 14:05:05 +02:00
|
|
|
int[] res = client.getIntArrValue("column_family/sstables/per_level/" + getCFName());
|
2015-12-03 11:15:15 +01:00
|
|
|
if (res.length == 0) {
|
|
|
|
// no sstable count
|
|
|
|
// should return null
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return res;
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the ratio of droppable tombstones to real columns (and non-droppable
|
|
|
|
* tombstones)
|
2015-06-21 08:46:29 +02:00
|
|
|
*
|
2015-06-04 12:35:57 +02:00
|
|
|
* @return ratio
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public double getDroppableTombstoneRatio() {
|
|
|
|
log(" getDroppableTombstoneRatio()");
|
2016-10-11 14:05:05 +02:00
|
|
|
return client.getDoubleValue("column_family/droppable_ratio/" + getCFName());
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the size of SSTables in "snapshots" subdirectory which aren't
|
|
|
|
* live anymore
|
|
|
|
*/
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
2015-06-04 12:35:57 +02:00
|
|
|
public long trueSnapshotsSize() {
|
|
|
|
log(" trueSnapshotsSize()");
|
2016-10-11 14:05:05 +02:00
|
|
|
return client.getLongValue("column_family/metrics/snapshots_size/" + getCFName());
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|
|
|
|
|
2015-06-24 10:15:26 +02:00
|
|
|
public String getKeyspace() {
|
|
|
|
return keyspace;
|
|
|
|
}
|
2016-10-11 14:05:05 +02:00
|
|
|
|
2016-08-17 10:30:04 +02:00
|
|
|
@Override
|
|
|
|
public String getTableName() {
|
|
|
|
log(" getTableName()");
|
|
|
|
return name;
|
|
|
|
}
|
2015-06-24 10:15:26 +02:00
|
|
|
|
2015-07-30 11:01:05 +02:00
|
|
|
@Override
|
2016-08-17 10:30:04 +02:00
|
|
|
public void forceMajorCompaction(boolean splitOutput) throws ExecutionException, InterruptedException {
|
|
|
|
log(" forceMajorCompaction(boolean) throws ExecutionException, InterruptedException");
|
|
|
|
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<String, String>();
|
2016-10-11 14:05:05 +02:00
|
|
|
queryParams.putSingle("value", valueOf(splitOutput));
|
|
|
|
client.post("column_family/major_compaction/" + getCFName(), queryParams);
|
2015-07-30 11:01:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2016-08-17 10:30:04 +02:00
|
|
|
public void setCompactionParametersJson(String options) {
|
|
|
|
log(" setCompactionParametersJson");
|
2016-11-01 10:44:17 +01:00
|
|
|
JsonReader reader = Json.createReaderFactory(null).createReader(new StringReader(options));
|
|
|
|
setCompactionParameters(
|
|
|
|
reader.readObject().entrySet().stream().collect(toMap(Map.Entry::getKey, e -> e.toString())));
|
2015-07-30 11:01:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2016-08-17 10:30:04 +02:00
|
|
|
public String getCompactionParametersJson() {
|
|
|
|
log(" getCompactionParametersJson");
|
2016-11-01 10:44:17 +01:00
|
|
|
JsonObjectBuilder b = createObjectBuilder();
|
|
|
|
getCompactionParameters().forEach(b::add);
|
|
|
|
return b.build().toString();
|
2015-07-30 11:01:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2016-08-17 10:30:04 +02:00
|
|
|
public void setCompactionParameters(Map<String, String> options) {
|
|
|
|
for (Map.Entry<String, String> e : options.entrySet()) {
|
2016-11-01 10:44:17 +01:00
|
|
|
// See below
|
|
|
|
if ("class".equals(e.getKey())) {
|
|
|
|
setCompactionStrategyClass(e.getValue());
|
|
|
|
} else {
|
|
|
|
throw new IllegalArgumentException(e.getKey());
|
|
|
|
}
|
2016-08-17 10:30:04 +02:00
|
|
|
}
|
2015-07-30 11:01:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2016-08-17 10:30:04 +02:00
|
|
|
public Map<String, String> getCompactionParameters() {
|
2016-11-01 10:44:17 +01:00
|
|
|
// We only currently support class. Here could have been a call that can
|
|
|
|
// be expanded only on the server side, but that raises controversy.
|
|
|
|
// Lets add some technical debt instead.
|
|
|
|
return Collections.singletonMap("class", getCompactionStrategyClass());
|
2016-08-17 10:30:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isCompactionDiskSpaceCheckEnabled() {
|
|
|
|
// TODO Auto-generated method stub
|
|
|
|
log(" isCompactionDiskSpaceCheckEnabled()");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void compactionDiskSpaceCheck(boolean enable) {
|
2016-10-11 14:05:05 +02:00
|
|
|
// TODO Auto-generated method stub
|
2016-08-17 10:30:04 +02:00
|
|
|
log(" compactionDiskSpaceCheck()");
|
2015-07-30 11:01:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
public void beginLocalSampling(String sampler_base, int capacity) {
|
|
|
|
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<String, String>();
|
|
|
|
queryParams.add("capacity", Integer.toString(capacity));
|
|
|
|
if (sampler_base.contains(":")) {
|
|
|
|
String[] parts = sampler_base.split(":");
|
|
|
|
queryParams.add("duration", parts[1]);
|
|
|
|
} else {
|
|
|
|
queryParams.add("duration", "10000");
|
|
|
|
}
|
|
|
|
startTableSampling(queryParams);
|
2016-08-17 10:30:04 +02:00
|
|
|
log(" beginLocalSampling()");
|
2015-07-30 11:01:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
public CompositeData finishLocalSampling(String samplerType, int count) throws OpenDataException {
|
2016-08-17 10:30:04 +02:00
|
|
|
log(" finishLocalSampling()");
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
|
|
|
|
waitUntilSamplingCompleted();
|
|
|
|
|
|
|
|
TabularDataSupport result = new TabularDataSupport(COUNTER_TYPE);
|
|
|
|
|
|
|
|
JsonArray counters = tableSamplerResult.getJsonArray((samplerType.equalsIgnoreCase("reads")) ? "read" : "write");
|
2020-12-11 16:17:57 +01:00
|
|
|
long cardinality = tableSamplerResult.getJsonNumber((samplerType.equalsIgnoreCase("reads")) ? "read_cardinality" : "write_cardinality").longValue();
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
long size = 0;
|
|
|
|
if (counters != null) {
|
2019-06-23 12:27:24 +02:00
|
|
|
size = (count > counters.size()) ? counters.size() : count;
|
|
|
|
for (int i = 0; i < size; i++) {
|
ColumnFamilyStore: Add an implementation for table sampling
This patch adds the implementation for begin and finish local sampling
of a column family.
There is a difference in the implementation of Cassandra API and Scylla.
In Cassandra and the JMX an external source start and stop the sampling.
In Scylla, a single API call start the sampling and return with the
result. In Scylla the API call always return sampling of the read and of
the writes.
To bridge the difference, the begin sampling command will use a Future
when calling the API. The finish method will wait for the future to end.
Because of the different implementation, it is possible that two
consecutive calls will be made to start sampling one for the read and
one for the write, similarly, two calls will be made to finish for read
and write.
The implementation would ignore the second call to start and will
store the result, so the second call to finish will be served from the
stored result.
Note, that the use of future is only for safety, the way we expect it to
work, the caller to the begin sampling will sleep anyhow while waiting
for the result.
To avoid breaking the MBean compatibility we piggyback the duration on
top of the sampler string.
If no duration is given, a default duration will be taken, this is also
just as a precaution, we will modify the nodetool implementation to
pass that information.
There is a known issue with cardinality, that will need to be addressed.
Also we return a value in the raw column to match what Cassandra JMX
returns, but it's a duplication of the partition key.
See scylladb/scylla#2811
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
Message-Id: <20190128143505.5241-1-amnon@scylladb.com>
2019-01-28 15:35:05 +01:00
|
|
|
JsonObject counter = counters.getJsonObject(i);
|
|
|
|
result.put(new CompositeDataSupport(COUNTER_COMPOSITE_TYPE, COUNTER_NAMES,
|
|
|
|
new Object[] { counter.getString("partition"), // raw
|
|
|
|
counter.getJsonNumber("count").longValue(), // count
|
|
|
|
counter.getJsonNumber("error").longValue(), // error
|
|
|
|
counter.getString("partition") })); // string
|
|
|
|
}
|
|
|
|
}
|
2020-12-11 16:17:57 +01:00
|
|
|
return new CompositeDataSupport(SAMPLING_RESULT, SAMPLER_NAMES, new Object[] { cardinality, result });
|
2015-07-30 11:01:05 +02:00
|
|
|
}
|
2015-06-04 12:35:57 +02:00
|
|
|
}
|