From 3e2c610577fc1716e6ee41ef6af0976587344615 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 12 Mar 2014 16:57:04 -0700 Subject: [PATCH 1/7] Fix stress to do proper counter reads Patch by Benedict Elliott Smith; reviewed by Pavel Yaskevich for CASSANDRA-6835 --- CHANGES.txt | 1 + .../apache/cassandra/utils/FBUtilities.java | 2 +- .../apache/cassandra/stress/Operation.java | 109 ++++++++++++------ .../apache/cassandra/stress/StressAction.java | 4 +- .../cassandra/stress/generatedata/RowGen.java | 1 + .../generatedata/RowGenDistributedSize.java | 7 ++ .../stress/operations/CqlCounterAdder.java | 17 ++- .../stress/operations/CqlCounterGetter.java | 9 +- .../operations/CqlIndexedRangeSlicer.java | 16 +-- .../stress/operations/CqlInserter.java | 10 +- .../stress/operations/CqlOperation.java | 73 +++++++----- .../stress/operations/CqlRangeSlicer.java | 8 +- .../stress/operations/CqlReader.java | 12 +- .../stress/operations/ThriftCounterAdder.java | 12 +- .../operations/ThriftCounterGetter.java | 15 +-- .../operations/ThriftIndexedRangeSlicer.java | 5 +- .../stress/operations/ThriftInserter.java | 6 +- .../stress/operations/ThriftMultiGetter.java | 3 +- .../stress/operations/ThriftRangeSlicer.java | 3 +- .../stress/operations/ThriftReader.java | 16 +-- .../cassandra/stress/settings/Command.java | 72 +++++++----- .../cassandra/stress/settings/Option.java | 1 + .../stress/settings/OptionDataGen.java | 5 + .../stress/settings/OptionDistribution.java | 13 ++- .../stress/settings/OptionMulti.java | 39 ++++++- .../stress/settings/OptionReplication.java | 2 +- .../stress/settings/OptionSimple.java | 2 +- .../stress/settings/SettingsColumn.java | 29 +++-- .../stress/settings/SettingsCommand.java | 30 ++--- .../stress/settings/SettingsCommandMixed.java | 46 ++++---- .../stress/settings/SettingsCommandMulti.java | 90 --------------- .../stress/settings/SettingsKey.java | 2 +- .../stress/settings/SettingsMisc.java | 4 +- .../stress/settings/SettingsMode.java | 40 +++++-- .../stress/settings/SettingsSchema.java | 7 +- .../stress/settings/SettingsTransport.java | 2 +- .../stress/settings/StressSettings.java | 30 +++-- .../stress/util/JavaDriverClient.java | 4 +- 38 files changed, 410 insertions(+), 337 deletions(-) delete mode 100644 tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMulti.java diff --git a/CHANGES.txt b/CHANGES.txt index 912e6afa6a..50e7da3275 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -15,6 +15,7 @@ * Fix ClassCastException for compact table with composites (CASSANDRA-6738) * Fix potentially repairing with wrong nodes (CASSANDRA-6808) * Change caching option syntax (CASSANDRA-6745) + * Fix stress to do proper counter reads (CASSANDRA-6835) Merged from 2.0: * Avoid race-prone second "scrub" of system keyspace (CASSANDRA-6797) * Pool CqlRecordWriter clients by inetaddress rather than Range diff --git a/src/java/org/apache/cassandra/utils/FBUtilities.java b/src/java/org/apache/cassandra/utils/FBUtilities.java index 0a94cc0736..7b574e2690 100644 --- a/src/java/org/apache/cassandra/utils/FBUtilities.java +++ b/src/java/org/apache/cassandra/utils/FBUtilities.java @@ -370,7 +370,7 @@ public class FBUtilities in = FBUtilities.class.getClassLoader().getResourceAsStream("org/apache/cassandra/config/version.properties"); if (in == null) { - return "Unknown"; + return System.getProperty("cassandra.releaseVersion", "Unknown"); } Properties props = new Properties(); props.load(in); diff --git a/tools/stress/src/org/apache/cassandra/stress/Operation.java b/tools/stress/src/org/apache/cassandra/stress/Operation.java index 4519b19036..33cca17df5 100644 --- a/tools/stress/src/org/apache/cassandra/stress/Operation.java +++ b/tools/stress/src/org/apache/cassandra/stress/Operation.java @@ -19,27 +19,16 @@ package org.apache.cassandra.stress; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import org.apache.cassandra.stress.generatedata.Distribution; import org.apache.cassandra.stress.generatedata.KeyGen; import org.apache.cassandra.stress.generatedata.RowGen; -import org.apache.cassandra.stress.operations.CqlCounterAdder; -import org.apache.cassandra.stress.operations.CqlCounterGetter; -import org.apache.cassandra.stress.operations.CqlIndexedRangeSlicer; -import org.apache.cassandra.stress.operations.CqlInserter; -import org.apache.cassandra.stress.operations.CqlMultiGetter; -import org.apache.cassandra.stress.operations.CqlRangeSlicer; -import org.apache.cassandra.stress.operations.CqlReader; -import org.apache.cassandra.stress.operations.ThriftCounterAdder; -import org.apache.cassandra.stress.operations.ThriftCounterGetter; -import org.apache.cassandra.stress.operations.ThriftIndexedRangeSlicer; -import org.apache.cassandra.stress.operations.ThriftInserter; -import org.apache.cassandra.stress.operations.ThriftMultiGetter; -import org.apache.cassandra.stress.operations.ThriftRangeSlicer; -import org.apache.cassandra.stress.operations.ThriftReader; import org.apache.cassandra.stress.settings.Command; import org.apache.cassandra.stress.settings.CqlVersion; import org.apache.cassandra.stress.settings.SettingsCommandMixed; @@ -49,6 +38,8 @@ import org.apache.cassandra.stress.util.ThriftClient; import org.apache.cassandra.stress.util.Timer; import org.apache.cassandra.thrift.ColumnParent; import org.apache.cassandra.thrift.InvalidRequestException; +import org.apache.cassandra.thrift.SlicePredicate; +import org.apache.cassandra.thrift.SliceRange; import org.apache.cassandra.transport.SimpleClient; import org.apache.cassandra.utils.ByteBufferUtil; @@ -79,6 +70,7 @@ public abstract class Operation public final Command type; public final KeyGen keyGen; public final RowGen rowGen; + public final Distribution counteradd; public final List columnParents; public final StressMetrics metrics; public final SettingsCommandMixed.CommandSelector commandSelector; @@ -99,19 +91,12 @@ public abstract class Operation commandSelector = null; substates = null; } + counteradd = settings.command.add.get(); this.settings = settings; this.keyGen = settings.keys.newKeyGen(); this.rowGen = settings.columns.newRowGen(); this.metrics = metrics; - if (!settings.columns.useSuperColumns) - columnParents = Collections.singletonList(new ColumnParent(settings.schema.columnFamily)); - else - { - ColumnParent[] cp = new ColumnParent[settings.columns.superColumns]; - for (int i = 0 ; i < cp.length ; i++) - cp[i] = new ColumnParent("Super1").setSuper_column(ByteBufferUtil.bytes("S" + i)); - columnParents = Arrays.asList(cp); - } + this.columnParents = columnParents(type, settings); } private State(Command type, State copy) @@ -120,13 +105,29 @@ public abstract class Operation this.timer = copy.timer; this.rowGen = copy.rowGen; this.keyGen = copy.keyGen; - this.columnParents = copy.columnParents; + this.columnParents = columnParents(type, copy.settings); this.metrics = copy.metrics; this.settings = copy.settings; + this.counteradd = copy.counteradd; this.substates = null; this.commandSelector = null; } + private List columnParents(Command type, StressSettings settings) + { + if (!settings.columns.useSuperColumns) + return Collections.singletonList(new ColumnParent(type.table)); + else + { + ColumnParent[] cp = new ColumnParent[settings.columns.superColumns]; + for (int i = 0 ; i < cp.length ; i++) + cp[i] = new ColumnParent(type.supertable).setSuper_column(ByteBufferUtil.bytes("S" + i)); + return Arrays.asList(cp); + } + } + + + public boolean isCql3() { return settings.mode.cqlVersion == CqlVersion.CQL3; @@ -172,6 +173,53 @@ public abstract class Operation return state.rowGen.generate(index, key); } + private int sliceStart(int count) + { + if (count == state.settings.columns.maxColumnsPerKey) + return 0; + return 1 + ThreadLocalRandom.current().nextInt(state.settings.columns.maxColumnsPerKey - count); + } + + protected SlicePredicate slicePredicate() + { + final SlicePredicate predicate = new SlicePredicate(); + if (state.settings.columns.slice) + { + int count = state.rowGen.count(index); + int start = sliceStart(count); + predicate.setSlice_range(new SliceRange() + .setStart(state.settings.columns.names.get(start)) + .setFinish(new byte[] {}) + .setReversed(false) + .setCount(count) + ); + } + else + predicate.setColumn_names(randomNames()); + return predicate; + } + + protected List randomNames() + { + int count = state.rowGen.count(index); + List src = state.settings.columns.names; + if (count == src.size()) + return src; + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + List r = new ArrayList<>(); + int c = 0, o = 0; + while (c < count && count + o < src.size()) + { + int leeway = src.size() - (count + o); + int spreadover = count - c; + o += Math.round(rnd.nextDouble() * (leeway / (double) spreadover)); + r.add(src.get(o + c++)); + } + while (c < count) + r.add(src.get(o + c++)); + return r; + } + /** * Run operation * @param client Cassandra Thrift client connection @@ -213,10 +261,11 @@ public abstract class Operation if (!success) { - error(String.format("Operation [%d] x%d key %s %s%n", + error(String.format("Operation [%d] x%d key %s (0x%s) %s%n", index, tries, run.key(), + ByteBufferUtil.bytesToHex(ByteBufferUtil.bytes(run.key())), (exceptionMessage == null) ? "Data returned was not validated" : "Error executing: " + exceptionMessage)); @@ -239,14 +288,4 @@ public abstract class Operation System.err.println(message); } - public static ByteBuffer getColumnNameBytes(int i) - { - return ByteBufferUtil.bytes("C" + i); - } - - public static String getColumnName(int i) - { - return "C" + i; - } - } diff --git a/tools/stress/src/org/apache/cassandra/stress/StressAction.java b/tools/stress/src/org/apache/cassandra/stress/StressAction.java index 94824ec0db..e7cdd0bb79 100644 --- a/tools/stress/src/org/apache/cassandra/stress/StressAction.java +++ b/tools/stress/src/org/apache/cassandra/stress/StressAction.java @@ -87,7 +87,7 @@ public class StressAction implements Runnable warmup(subtype, command); return; case MULTI: - int keysAtOnce = ((SettingsCommandMulti) command).keysAtOnce; + int keysAtOnce = command.keysAtOnce; iterations = Math.min(50000, (int) Math.ceil(500000d / keysAtOnce)); break; default: @@ -298,6 +298,8 @@ public class StressAction implements Runnable case SIMPLE_NATIVE: op.run(sclient); break; + case THRIFT: + case THRIFT_SMART: default: op.run(tclient); } diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java index cb0dc1c742..9c6ca43ee7 100644 --- a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java +++ b/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java @@ -46,6 +46,7 @@ public abstract class RowGen // these byte[] may be re-used abstract List getColumns(long operationIndex); + abstract public int count(long operationIndex); abstract public boolean isDeterministic(); diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java index eecbc7ee0d..fffad2f05a 100644 --- a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java +++ b/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java @@ -51,6 +51,8 @@ public class RowGenDistributedSize extends RowGen this.sizeDistribution = sizeDistribution; ret = new ByteBuffer[(int) countDistribution.maxValue()]; sizes = new int[ret.length]; + // TODO: should keep it deterministic in event that count distribution is not, but size and dataGen are, so that + // we simply need to generate the correct selection of columns this.isDeterministic = dataGen.isDeterministic() && countDistribution.maxValue() == countDistribution.minValue() && sizeDistribution.minValue() == sizeDistribution.maxValue(); } @@ -100,6 +102,11 @@ public class RowGenDistributedSize extends RowGen return Arrays.asList(ret).subList(0, count); } + public int count(long operationIndex) + { + return (int) countDistribution.next(); + } + @Override public boolean isDeterministic() { diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java index aae99b596a..9a8c37de2f 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java @@ -22,9 +22,12 @@ package org.apache.cassandra.stress.operations; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.apache.cassandra.utils.ByteBufferUtil; + public class CqlCounterAdder extends CqlOperation { public CqlCounterAdder(State state, long idx) @@ -35,7 +38,7 @@ public class CqlCounterAdder extends CqlOperation @Override protected String buildQuery() { - String counterCF = state.isCql2() ? "Counter1" : "Counter3"; + String counterCF = state.isCql2() ? state.type.table : "Counter3"; StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(counterCF)); @@ -50,20 +53,24 @@ public class CqlCounterAdder extends CqlOperation if (i > 0) query.append(","); - query.append('C').append(i).append("=C").append(i).append("+1"); + query.append('C').append(i).append("=C").append(i).append("+?"); } query.append(" WHERE KEY=?"); return query.toString(); } @Override - protected List getQueryParameters(byte[] key) + protected List getQueryParameters(byte[] key) { - return Collections.singletonList(ByteBuffer.wrap(key)); + final List list = new ArrayList<>(); + for (int i = 0; i < state.settings.columns.maxColumnsPerKey; i++) + list.add(state.counteradd.next()); + list.add(ByteBuffer.wrap(key)); + return list; } @Override - protected CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) + protected CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) { return new CqlRunOpAlwaysSucceed(client, query, queryId, params, keyid, key, 1); } diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java index 31fd20d441..88d622ebbb 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java @@ -34,9 +34,9 @@ public class CqlCounterGetter extends CqlOperation } @Override - protected List getQueryParameters(byte[] key) + protected List getQueryParameters(byte[] key) { - return Collections.singletonList(ByteBuffer.wrap(key)); + return Collections.singletonList(ByteBuffer.wrap(key)); } @Override @@ -44,12 +44,13 @@ public class CqlCounterGetter extends CqlOperation { StringBuilder query = new StringBuilder("SELECT "); + // TODO: obey slice/noslice option (instead of always slicing) if (state.isCql2()) query.append("FIRST ").append(state.settings.columns.maxColumnsPerKey).append(" ''..''"); else query.append("*"); - String counterCF = state.isCql2() ? "Counter1" : "Counter3"; + String counterCF = state.isCql2() ? state.type.table : "Counter3"; query.append(" FROM ").append(wrapInQuotesIfRequired(counterCF)); @@ -60,7 +61,7 @@ public class CqlCounterGetter extends CqlOperation } @Override - protected CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) + protected CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) { return new CqlRunOpTestNonEmpty(client, query, queryId, params, keyid, key); } diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java index ff43322bca..c971844abd 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java @@ -26,7 +26,6 @@ import java.nio.ByteBuffer; import java.util.Arrays; import java.util.List; -import org.apache.cassandra.stress.settings.SettingsCommandMulti; import org.apache.cassandra.utils.FBUtilities; public class CqlIndexedRangeSlicer extends CqlOperation @@ -40,7 +39,7 @@ public class CqlIndexedRangeSlicer extends CqlOperation } @Override - protected List getQueryParameters(byte[] key) + protected List getQueryParameters(byte[] key) { throw new UnsupportedOperationException(); } @@ -55,14 +54,15 @@ public class CqlIndexedRangeSlicer extends CqlOperation else query.append("*"); - query.append(" FROM Standard1"); + query.append(" FROM "); + query.append(wrapInQuotesIfRequired(state.type.table)); if (state.isCql2()) query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel); - final String columnName = getColumnName(1); + final String columnName = (state.settings.columns.namestrs.get(1)); query.append(" WHERE ").append(columnName).append("=?") - .append(" AND KEY > ? LIMIT ").append(((SettingsCommandMulti)state.settings.command).keysAtOnce); + .append(" AND KEY > ? LIMIT ").append(state.settings.command.keysAtOnce); return query.toString(); } @@ -76,7 +76,7 @@ public class CqlIndexedRangeSlicer extends CqlOperation int rowCount; do { - List params = Arrays.asList(value, ByteBuffer.wrap(minKey)); + List params = Arrays.asList(value, ByteBuffer.wrap(minKey)); CqlRunOp op = run(client, params, value, new String(value.array())); byte[][] keys = op.result; rowCount = keys.length; @@ -88,7 +88,7 @@ public class CqlIndexedRangeSlicer extends CqlOperation private final class IndexedRangeSliceRunOp extends CqlRunOpFetchKeys { - protected IndexedRangeSliceRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) + protected IndexedRangeSliceRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) { super(client, query, queryId, params, keyid, key); } @@ -101,7 +101,7 @@ public class CqlIndexedRangeSlicer extends CqlOperation } @Override - protected CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) + protected CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) { return new IndexedRangeSliceRunOp(client, query, queryId, params, keyid, key); } diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java index 8d964f57b9..71cdadfa9a 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java @@ -33,12 +33,14 @@ public class CqlInserter extends CqlOperation public CqlInserter(State state, long idx) { super(state, idx); + if (state.settings.columns.useTimeUUIDComparator) + throw new IllegalStateException("Cannot use TimeUUID Comparator with CQL"); } @Override protected String buildQuery() { - StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(state.settings.schema.columnFamily)); + StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(state.type.table)); if (state.isCql2()) query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel); @@ -69,9 +71,9 @@ public class CqlInserter extends CqlOperation } @Override - protected List getQueryParameters(byte[] key) + protected List getQueryParameters(byte[] key) { - final ArrayList queryParams = new ArrayList<>(); + final ArrayList queryParams = new ArrayList<>(); final List values = generateColumnValues(ByteBuffer.wrap(key)); queryParams.addAll(values); queryParams.add(ByteBuffer.wrap(key)); @@ -79,7 +81,7 @@ public class CqlInserter extends CqlOperation } @Override - protected CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) + protected CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) { return new CqlRunOpAlwaysSucceed(client, query, queryId, params, keyid, key, 1); } diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java index b17f52042a..5b271464bf 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java @@ -20,6 +20,7 @@ package org.apache.cassandra.stress.operations; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -44,9 +45,9 @@ import org.apache.thrift.TException; public abstract class CqlOperation extends Operation { - protected abstract List getQueryParameters(byte[] key); + protected abstract List getQueryParameters(byte[] key); protected abstract String buildQuery(); - protected abstract CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String id, ByteBuffer key); + protected abstract CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String id, ByteBuffer key); public CqlOperation(State state, long idx) { @@ -55,9 +56,11 @@ public abstract class CqlOperation extends Operation throw new IllegalStateException("Super columns are not implemented for CQL"); if (state.settings.columns.variableColumnCount) throw new IllegalStateException("Variable column counts are not implemented for CQL"); + if (state.settings.columns.useTimeUUIDComparator) + throw new IllegalStateException("Cannot use TimeUUID Comparator with CQL"); } - protected CqlRunOp run(final ClientWrapper client, final List queryParams, final ByteBuffer key, final String keyid) throws IOException + protected CqlRunOp run(final ClientWrapper client, final List queryParams, final ByteBuffer key, final String keyid) throws IOException { final CqlRunOp op; if (state.settings.mode.style == ConnectionStyle.CQL_PREPARED) @@ -99,7 +102,7 @@ public abstract class CqlOperation extends Operation protected void run(final ClientWrapper client) throws IOException { final byte[] key = getKey().array(); - final List queryParams = getQueryParameters(key); + final List queryParams = getQueryParameters(key); run(client, queryParams, ByteBuffer.wrap(key), new String(key)); } @@ -111,7 +114,7 @@ public abstract class CqlOperation extends Operation final int keyCount; - protected CqlRunOpAlwaysSucceed(ClientWrapper client, String query, Object queryId, List params, String id, ByteBuffer key, int keyCount) + protected CqlRunOpAlwaysSucceed(ClientWrapper client, String query, Object queryId, List params, String id, ByteBuffer key, int keyCount) { super(client, query, queryId, RowCountHandler.INSTANCE, params, id, key); this.keyCount = keyCount; @@ -134,7 +137,7 @@ public abstract class CqlOperation extends Operation protected final class CqlRunOpTestNonEmpty extends CqlRunOp { - protected CqlRunOpTestNonEmpty(ClientWrapper client, String query, Object queryId, List params, String id, ByteBuffer key) + protected CqlRunOpTestNonEmpty(ClientWrapper client, String query, Object queryId, List params, String id, ByteBuffer key) { super(client, query, queryId, RowCountHandler.INSTANCE, params, id, key); } @@ -156,7 +159,7 @@ public abstract class CqlOperation extends Operation protected abstract class CqlRunOpFetchKeys extends CqlRunOp { - protected CqlRunOpFetchKeys(ClientWrapper client, String query, Object queryId, List params, String id, ByteBuffer key) + protected CqlRunOpFetchKeys(ClientWrapper client, String query, Object queryId, List params, String id, ByteBuffer key) { super(client, query, queryId, KeysHandler.INSTANCE, params, id, key); } @@ -175,7 +178,7 @@ public abstract class CqlOperation extends Operation final List> expect; // a null value for an item in expect means we just check the row is present - protected CqlRunOpMatchResults(ClientWrapper client, String query, Object queryId, List params, String id, ByteBuffer key, List> expect) + protected CqlRunOpMatchResults(ClientWrapper client, String query, Object queryId, List params, String id, ByteBuffer key, List> expect) { super(client, query, queryId, RowsHandler.INSTANCE, params, id, key); this.expect = expect; @@ -209,13 +212,13 @@ public abstract class CqlOperation extends Operation final ClientWrapper client; final String query; final Object queryId; - final List params; + final List params; final String id; final ByteBuffer key; final ResultHandler handler; V result; - private CqlRunOp(ClientWrapper client, String query, Object queryId, ResultHandler handler, List params, String id, ByteBuffer key) + private CqlRunOp(ClientWrapper client, String query, Object queryId, ResultHandler handler, List params, String id, ByteBuffer key) { this.client = client; this.query = query; @@ -287,8 +290,8 @@ public abstract class CqlOperation extends Operation protected interface ClientWrapper { Object createPreparedStatement(String cqlQuery) throws TException; - V execute(Object preparedStatementId, ByteBuffer key, List queryParams, ResultHandler handler) throws TException; - V execute(String query, ByteBuffer key, List queryParams, ResultHandler handler) throws TException; + V execute(Object preparedStatementId, ByteBuffer key, List queryParams, ResultHandler handler) throws TException; + V execute(String query, ByteBuffer key, List queryParams, ResultHandler handler) throws TException; } private final class JavaDriverWrapper implements ClientWrapper @@ -300,14 +303,14 @@ public abstract class CqlOperation extends Operation } @Override - public V execute(String query, ByteBuffer key, List queryParams, ResultHandler handler) + public V execute(String query, ByteBuffer key, List queryParams, ResultHandler handler) { String formattedQuery = formatCqlQuery(query, queryParams, state.isCql3()); return handler.javaDriverHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(state.settings.command.consistencyLevel))); } @Override - public V execute(Object preparedStatementId, ByteBuffer key, List queryParams, ResultHandler handler) + public V execute(Object preparedStatementId, ByteBuffer key, List queryParams, ResultHandler handler) { return handler.javaDriverHandler().apply( client.executePrepared( @@ -332,19 +335,19 @@ public abstract class CqlOperation extends Operation } @Override - public V execute(String query, ByteBuffer key, List queryParams, ResultHandler handler) + public V execute(String query, ByteBuffer key, List queryParams, ResultHandler handler) { String formattedQuery = formatCqlQuery(query, queryParams, state.isCql3()); return handler.thriftHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(state.settings.command.consistencyLevel))); } @Override - public V execute(Object preparedStatementId, ByteBuffer key, List queryParams, ResultHandler handler) + public V execute(Object preparedStatementId, ByteBuffer key, List queryParams, ResultHandler handler) { return handler.thriftHandler().apply( client.executePrepared( (byte[]) preparedStatementId, - queryParams, + toByteBufferParams(queryParams), ThriftConversion.fromThrift(state.settings.command.consistencyLevel))); } @@ -365,7 +368,7 @@ public abstract class CqlOperation extends Operation } @Override - public V execute(String query, ByteBuffer key, List queryParams, ResultHandler handler) throws TException + public V execute(String query, ByteBuffer key, List queryParams, ResultHandler handler) throws TException { String formattedQuery = formatCqlQuery(query, queryParams, true); return handler.simpleNativeHandler().apply( @@ -374,11 +377,11 @@ public abstract class CqlOperation extends Operation } @Override - public V execute(Object preparedStatementId, ByteBuffer key, List queryParams, ResultHandler handler) throws TException + public V execute(Object preparedStatementId, ByteBuffer key, List queryParams, ResultHandler handler) throws TException { Integer id = (Integer) preparedStatementId; return handler.simpleNativeHandler().apply( - client.execute_prepared_cql3_query(id, key, queryParams, state.settings.command.consistencyLevel) + client.execute_prepared_cql3_query(id, key, toByteBufferParams(queryParams), state.settings.command.consistencyLevel) ); } @@ -399,7 +402,7 @@ public abstract class CqlOperation extends Operation } @Override - public V execute(String query, ByteBuffer key, List queryParams, ResultHandler handler) throws TException + public V execute(String query, ByteBuffer key, List queryParams, ResultHandler handler) throws TException { String formattedQuery = formatCqlQuery(query, queryParams, false); return handler.simpleNativeHandler().apply( @@ -408,11 +411,11 @@ public abstract class CqlOperation extends Operation } @Override - public V execute(Object preparedStatementId, ByteBuffer key, List queryParams, ResultHandler handler) throws TException + public V execute(Object preparedStatementId, ByteBuffer key, List queryParams, ResultHandler handler) throws TException { Integer id = (Integer) preparedStatementId; return handler.simpleNativeHandler().apply( - client.execute_prepared_cql_query(id, key, queryParams) + client.execute_prepared_cql_query(id, key, toByteBufferParams(queryParams)) ); } @@ -647,7 +650,7 @@ public abstract class CqlOperation extends Operation * @param parms sequence of string query parameters * @return formatted CQL query string */ - private static String formatCqlQuery(String query, List parms, boolean isCql3) + private static String formatCqlQuery(String query, List parms, boolean isCql3) { int marker, position = 0; StringBuilder result = new StringBuilder(); @@ -655,10 +658,14 @@ public abstract class CqlOperation extends Operation if (-1 == (marker = query.indexOf('?')) || parms.size() == 0) return query; - for (ByteBuffer parm : parms) + for (Object parm : parms) { result.append(query.substring(position, marker)); - result.append(getUnQuotedCqlBlob(parm, isCql3)); + if (parm instanceof ByteBuffer) + result.append(getUnQuotedCqlBlob((ByteBuffer) parm, isCql3)); + else if (parm instanceof Long) + result.append(parm.toString()); + else throw new AssertionError(); position = marker + 1; if (-1 == (marker = query.indexOf('?', position + 1))) @@ -671,6 +678,20 @@ public abstract class CqlOperation extends Operation return result.toString(); } + private static List toByteBufferParams(List params) + { + List r = new ArrayList<>(); + for (Object param : params) + { + if (param instanceof ByteBuffer) + r.add((ByteBuffer) param); + else if (param instanceof Long) + r.add(ByteBufferUtil.bytes((Long) param)); + else throw new AssertionError(); + } + return r; + } + protected String wrapInQuotesIfRequired(String string) { return state.settings.mode.cqlVersion == CqlVersion.CQL3 diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java index 76ba9663bb..16cdff31b6 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java @@ -33,16 +33,16 @@ public class CqlRangeSlicer extends CqlOperation } @Override - protected List getQueryParameters(byte[] key) + protected List getQueryParameters(byte[] key) { - return Collections.singletonList(ByteBuffer.wrap(key)); + return Collections.singletonList(ByteBuffer.wrap(key)); } @Override protected String buildQuery() { StringBuilder query = new StringBuilder("SELECT FIRST ").append(state.settings.columns.maxColumnsPerKey) - .append(" ''..'' FROM ").append(state.settings.schema.columnFamily); + .append(" ''..'' FROM ").append(wrapInQuotesIfRequired(state.type.table)); if (state.isCql2()) query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel); @@ -51,7 +51,7 @@ public class CqlRangeSlicer extends CqlOperation } @Override - protected CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) + protected CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) { return new CqlRunOpTestNonEmpty(client, query, queryId, params, keyid, key); } diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java index 44da43f25b..4b8d69e759 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java @@ -40,7 +40,7 @@ public class CqlReader extends CqlOperation { StringBuilder query = new StringBuilder("SELECT "); - if (state.settings.columns.names == null) + if (state.settings.columns.slice) { if (state.isCql2()) query.append("FIRST ").append(state.settings.columns.maxColumnsPerKey).append(" ''..''"); @@ -57,7 +57,7 @@ public class CqlReader extends CqlOperation } } - query.append(" FROM ").append(wrapInQuotesIfRequired(state.settings.schema.columnFamily)); + query.append(" FROM ").append(wrapInQuotesIfRequired(state.type.table)); if (state.isCql2()) query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel); @@ -66,21 +66,21 @@ public class CqlReader extends CqlOperation } @Override - protected List getQueryParameters(byte[] key) + protected List getQueryParameters(byte[] key) { if (state.settings.columns.names != null) { - final List queryParams = new ArrayList<>(); + final List queryParams = new ArrayList<>(); for (ByteBuffer name : state.settings.columns.names) queryParams.add(name); queryParams.add(ByteBuffer.wrap(key)); return queryParams; } - return Collections.singletonList(ByteBuffer.wrap(key)); + return Collections.singletonList(ByteBuffer.wrap(key)); } @Override - protected CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) + protected CqlRunOp buildRunOp(ClientWrapper client, String query, Object queryId, List params, String keyid, ByteBuffer key) { List expectRow = state.rowGen.isDeterministic() ? generateColumnValues(key) : null; return new CqlRunOpMatchResults(client, query, queryId, params, keyid, key, Arrays.asList(expectRow)); diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java index 26695a6fee..9bfe4406a3 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java @@ -23,6 +23,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; import org.apache.cassandra.stress.Operation; import org.apache.cassandra.stress.util.ThriftClient; @@ -33,15 +35,13 @@ public class ThriftCounterAdder extends Operation public ThriftCounterAdder(State state, long index) { super(state, index); - if (state.settings.columns.variableColumnCount) - throw new IllegalStateException("Variable column counts not supported for counters"); } public void run(final ThriftClient client) throws IOException { List columns = new ArrayList<>(); - for (int i = 0; i < state.settings.columns.maxColumnsPerKey; i++) - columns.add(new CounterColumn(getColumnNameBytes(i), 1L)); + for (ByteBuffer name : randomNames()) + columns.add(new CounterColumn(name, state.counteradd.next())); Map> row; if (state.settings.columns.useSuperColumns) @@ -53,7 +53,7 @@ public class ThriftCounterAdder extends Operation ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setCounter_super_column(csc); mutations.add(new Mutation().setColumn_or_supercolumn(cosc)); } - row = Collections.singletonMap("SuperCounter1", mutations); + row = Collections.singletonMap(state.type.supertable, mutations); } else { @@ -63,7 +63,7 @@ public class ThriftCounterAdder extends Operation ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setCounter_column(c); mutations.add(new Mutation().setColumn_or_supercolumn(cosc)); } - row = Collections.singletonMap("Counter1", mutations); + row = Collections.singletonMap(state.type.table, mutations); } final ByteBuffer key = getKey(); diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java index 8567edd01d..6e36a28e48 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java @@ -19,6 +19,7 @@ package org.apache.cassandra.stress.operations; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.List; import org.apache.cassandra.stress.Operation; import org.apache.cassandra.stress.util.ThriftClient; @@ -31,20 +32,11 @@ public class ThriftCounterGetter extends Operation public ThriftCounterGetter(State state, long index) { super(state, index); - if (state.settings.columns.variableColumnCount) - throw new IllegalStateException("Variable column counts not supported for counters"); } public void run(final ThriftClient client) throws IOException { - SliceRange sliceRange = new SliceRange(); - // start/finish - sliceRange.setStart(new byte[] {}).setFinish(new byte[] {}); - // reversed/count - sliceRange.setReversed(false).setCount(state.settings.columns.maxColumnsPerKey); - // initialize SlicePredicate with existing SliceRange - final SlicePredicate predicate = new SlicePredicate().setSlice_range(sliceRange); - + final SlicePredicate predicate = slicePredicate(); final ByteBuffer key = getKey(); for (final ColumnParent parent : state.columnParents) { @@ -54,7 +46,8 @@ public class ThriftCounterGetter extends Operation @Override public boolean run() throws Exception { - return client.get_slice(key, parent, predicate, state.settings.command.consistencyLevel).size() != 0; + List r = client.get_slice(key, parent, predicate, state.settings.command.consistencyLevel); + return r != null && r.size() > 0; } @Override diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java index 6eab209c78..8c8ec31c18 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java @@ -23,7 +23,6 @@ import java.util.Arrays; import java.util.List; import org.apache.cassandra.stress.Operation; -import org.apache.cassandra.stress.settings.SettingsCommandMulti; import org.apache.cassandra.stress.util.ThriftClient; import org.apache.cassandra.thrift.*; import org.apache.cassandra.utils.ByteBufferUtil; @@ -52,7 +51,7 @@ public class ThriftIndexedRangeSlicer extends Operation final List columns = generateColumnValues(getKey()); final ColumnParent parent = state.columnParents.get(0); - final ByteBuffer columnName = getColumnNameBytes(1); + final ByteBuffer columnName = state.settings.columns.names.get(1); final ByteBuffer value = columns.get(1); // only C1 column is indexed IndexExpression expression = new IndexExpression(columnName, IndexOperator.EQ, value); @@ -64,7 +63,7 @@ public class ThriftIndexedRangeSlicer extends Operation final boolean first = minKey.length == 0; final IndexClause clause = new IndexClause(Arrays.asList(expression), ByteBuffer.wrap(minKey), - ((SettingsCommandMulti) state.settings.command).keysAtOnce); + state.settings.command.keysAtOnce); timeWithRetry(new RunOp() { diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java index b107f261ed..7077a95049 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java @@ -53,7 +53,7 @@ public final class ThriftInserter extends Operation ColumnOrSuperColumn column = new ColumnOrSuperColumn().setColumn(c); mutations.add(new Mutation().setColumn_or_supercolumn(column)); } - row = Collections.singletonMap(state.settings.schema.columnFamily, mutations); + row = Collections.singletonMap(state.type.table, mutations); } else { @@ -64,7 +64,7 @@ public final class ThriftInserter extends Operation final ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setSuper_column(s); mutations.add(new Mutation().setColumn_or_supercolumn(cosc)); } - row = Collections.singletonMap("Super1", mutations); + row = Collections.singletonMap(state.settings.command.type.supertable, mutations); } final Map>> record = Collections.singletonMap(key, row); @@ -104,7 +104,7 @@ public final class ThriftInserter extends Operation // TODO : consider randomly allocating column names in case where have fewer than max columns // but need to think about implications for indexes / indexed range slicer / other knock on effects for (int i = 0 ; i < values.size() ; i++) - columns.add(new Column(getColumnNameBytes(i))); + columns.add(new Column(state.settings.columns.names.get(i))); for (int i = 0 ; i < values.size() ; i++) columns.get(i) diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java index 01c7325000..d8e0117e98 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java @@ -22,7 +22,6 @@ import java.nio.ByteBuffer; import java.util.List; import org.apache.cassandra.stress.Operation; -import org.apache.cassandra.stress.settings.SettingsCommandMulti; import org.apache.cassandra.stress.util.ThriftClient; import org.apache.cassandra.thrift.ColumnParent; import org.apache.cassandra.thrift.SlicePredicate; @@ -50,7 +49,7 @@ public final class ThriftMultiGetter extends Operation ) ); - final List keys = getKeys(((SettingsCommandMulti) state.settings.command).keysAtOnce); + final List keys = getKeys(state.settings.command.keysAtOnce); for (final ColumnParent parent : state.columnParents) { diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java index ce6c8cd4ca..021c4e842e 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.nio.ByteBuffer; import org.apache.cassandra.stress.Operation; -import org.apache.cassandra.stress.settings.SettingsCommandMulti; import org.apache.cassandra.stress.util.ThriftClient; import org.apache.cassandra.thrift.ColumnParent; import org.apache.cassandra.thrift.KeyRange; @@ -55,7 +54,7 @@ public final class ThriftRangeSlicer extends Operation new KeyRange(state.settings.columns.maxColumnsPerKey) .setStart_key(start) .setEnd_key(ByteBufferUtil.EMPTY_BYTE_BUFFER) - .setCount(((SettingsCommandMulti)state.settings.command).keysAtOnce); + .setCount(state.settings.command.keysAtOnce); for (final ColumnParent parent : state.columnParents) { diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java index c50843ff8e..dccf4696bc 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java @@ -19,7 +19,6 @@ package org.apache.cassandra.stress.operations; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.ArrayList; import java.util.List; import org.apache.cassandra.stress.Operation; @@ -27,7 +26,6 @@ import org.apache.cassandra.stress.util.ThriftClient; import org.apache.cassandra.thrift.ColumnOrSuperColumn; import org.apache.cassandra.thrift.ColumnParent; import org.apache.cassandra.thrift.SlicePredicate; -import org.apache.cassandra.thrift.SliceRange; import org.apache.cassandra.thrift.SuperColumn; public final class ThriftReader extends Operation @@ -40,17 +38,7 @@ public final class ThriftReader extends Operation public void run(final ThriftClient client) throws IOException { - final SlicePredicate predicate = new SlicePredicate(); - if (state.settings.columns.names == null) - predicate.setSlice_range(new SliceRange() - .setStart(new byte[] {}) - .setFinish(new byte[] {}) - .setReversed(false) - .setCount(state.settings.columns.maxColumnsPerKey) - ); - else // see CASSANDRA-3064 about why this is useful - predicate.setColumn_names(state.settings.columns.names); - + final SlicePredicate predicate = slicePredicate(); final ByteBuffer key = getKey(); final List expect = state.rowGen.isDeterministic() ? generateColumnValues(key) : null; for (final ColumnParent parent : state.columnParents) @@ -63,6 +51,8 @@ public final class ThriftReader extends Operation List row = client.get_slice(key, parent, predicate, state.settings.command.consistencyLevel); if (expect == null) return !row.isEmpty(); + if (row == null) + return false; if (!state.settings.columns.useSuperColumns) { if (row.size() != expect.size()) diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/Command.java b/tools/stress/src/org/apache/cassandra/stress/settings/Command.java index 60b65f7b8c..d0350ad972 100644 --- a/tools/stress/src/org/apache/cassandra/stress/settings/Command.java +++ b/tools/stress/src/org/apache/cassandra/stress/settings/Command.java @@ -27,54 +27,46 @@ import java.util.Map; public enum Command { - READ(false, - SettingsCommand.helpPrinter("read"), + READ(false, "Standard1", "Super1", "Multiple concurrent reads - the cluster must first be populated by a write test", CommandCategory.BASIC ), - WRITE(true, - SettingsCommand.helpPrinter("write"), + WRITE(true, "Standard1", "Super1", "insert", "Multiple concurrent writes against the cluster", CommandCategory.BASIC ), - MIXED(true, - SettingsCommandMixed.helpPrinter(), + MIXED(true, null, null, "Interleaving of any basic commands, with configurable ratio and distribution - the cluster must first be populated by a write test", CommandCategory.MIXED ), - RANGESLICE(false, - SettingsCommandMulti.helpPrinter("range_slice"), + RANGESLICE(false, "Standard1", "Super1", "Range slice queries - the cluster must first be populated by a write test", CommandCategory.MULTI ), - IRANGESLICE(false, - SettingsCommandMulti.helpPrinter("indexed_range_slice"), + IRANGESLICE(false, "Standard1", "Super1", "Range slice queries through a secondary index. The cluster must first be populated by a write test, with indexing enabled.", - CommandCategory.MULTI + CommandCategory.BASIC ), - READMULTI(false, - SettingsCommandMulti.helpPrinter("readmulti"), + READMULTI(false, "Standard1", "Super1", "multi_read", "Multiple concurrent reads fetching multiple rows at once. The cluster must first be populated by a write test.", CommandCategory.MULTI ), - COUNTERWRITE(true, - SettingsCommand.helpPrinter("counteradd"), + COUNTERWRITE(true, "Counter1", "SuperCounter1", "counter_add", "Multiple concurrent updates of counters.", CommandCategory.BASIC ), - COUNTERREAD(false, - SettingsCommand.helpPrinter("counterread"), + COUNTERREAD(false, "Counter1", "SuperCounter1", "counter_get", "Multiple concurrent reads of counters. The cluster must first be populated by a counterwrite test.", CommandCategory.BASIC ), - HELP(false, SettingsMisc.helpHelpPrinter(), "-?", "Print help for a command or option", null), - PRINT(false, SettingsMisc.printHelpPrinter(), "Inspect the output of a distribution definition", null), - LEGACY(false, Legacy.helpPrinter(), "Legacy support mode", null) + HELP(false, null, null, "-?", "Print help for a command or option", null), + PRINT(false, null, null, "Inspect the output of a distribution definition", null), + LEGACY(false, null, null, "Legacy support mode", null) ; @@ -100,23 +92,49 @@ public enum Command public final CommandCategory category; public final String extraName; public final String description; - public final Runnable helpPrinter; + public final String table; + public final String supertable; - Command(boolean updates, Runnable helpPrinter, String description, CommandCategory category) + Command(boolean updates, String table, String supertable, String description, CommandCategory category) { - this(updates, helpPrinter, null, description, category); + this(updates, table, supertable, null, description, category); } - Command(boolean updates, Runnable helpPrinter, String extra, String description, CommandCategory category) + + Command(boolean updates, String table, String supertable, String extra, String description, CommandCategory category) { + this.table = table; + this.supertable = supertable; this.updates = updates; this.category = category; - this.helpPrinter = helpPrinter; this.extraName = extra; this.description = description; } + public void printHelp() { - helpPrinter.run(); + helpPrinter().run(); } -} + public final Runnable helpPrinter() + { + switch (this) + { + case PRINT: + return SettingsMisc.printHelpPrinter(); + case HELP: + return SettingsMisc.helpHelpPrinter(); + case LEGACY: + return Legacy.helpPrinter(); + } + switch (category) + { + case BASIC: + case MULTI: + return SettingsCommand.helpPrinter(this); + case MIXED: + return SettingsCommandMixed.helpPrinter(); + } + throw new AssertionError(); + } + +} \ No newline at end of file diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/Option.java b/tools/stress/src/org/apache/cassandra/stress/settings/Option.java index bc663f56dc..a9e669ce45 100644 --- a/tools/stress/src/org/apache/cassandra/stress/settings/Option.java +++ b/tools/stress/src/org/apache/cassandra/stress/settings/Option.java @@ -31,6 +31,7 @@ abstract class Option abstract String shortDisplay(); abstract String longDisplay(); abstract List multiLineDisplay(); + abstract boolean setByUser(); public int hashCode() { diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java index f8ced72e06..bde2b104d2 100644 --- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java +++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java @@ -83,6 +83,11 @@ class OptionDataGen extends Option return factory != null || defaultFactory != null; } + public boolean setByUser() + { + return factory != null; + } + @Override public String shortDisplay() { diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java index feaf017ff9..b84bbc2c87 100644 --- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java +++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java @@ -43,11 +43,13 @@ class OptionDistribution extends Option final String prefix; private String spec; private final String defaultSpec; + private final String description; - public OptionDistribution(String prefix, String defaultSpec) + public OptionDistribution(String prefix, String defaultSpec, String description) { this.prefix = prefix; this.defaultSpec = defaultSpec; + this.description = description; } @Override @@ -88,7 +90,7 @@ class OptionDistribution extends Option public String longDisplay() { - return shortDisplay() + ": Specify a mathematical distribution"; + return shortDisplay() + ": " + description; } @Override @@ -105,10 +107,15 @@ class OptionDistribution extends Option ); } + boolean setByUser() + { + return spec != null; + } + @Override public String shortDisplay() { - return prefix + "DIST(?)"; + return (defaultSpec != null ? "[" : "") + prefix + "DIST(?)" + (defaultSpec != null ? "]" : ""); } private static final Map LOOKUP; diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java index 7074dc6a69..60faad87f1 100644 --- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java +++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java @@ -100,7 +100,7 @@ abstract class OptionMulti extends Option StringBuilder sb = new StringBuilder(); sb.append(name); sb.append("("); - for (Option option : options()) + for (Option option : delegate.options()) { sb.append(option); sb.append(","); @@ -112,7 +112,7 @@ abstract class OptionMulti extends Option @Override public String shortDisplay() { - return name + "(?)"; + return (happy() ? "[" : "") + name + "(?)" + (happy() ? "]" : ""); } @Override @@ -121,7 +121,7 @@ abstract class OptionMulti extends Option StringBuilder sb = new StringBuilder(); sb.append(name); sb.append("("); - for (Option opt : options()) + for (Option opt : delegate.options()) { sb.append(opt.shortDisplay()); } @@ -181,6 +181,37 @@ abstract class OptionMulti extends Option { return Collections.emptyList(); } - }; + + boolean setByUser() + { + return !options.isEmpty(); + } + } + + List