You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by be...@apache.org on 2014/07/07 19:34:24 UTC
[01/23] git commit: Fix test built
Repository: cassandra
Updated Branches:
refs/heads/cassandra-2.1 4e53152c5 -> 35b88c560
refs/heads/cassandra-2.1.0 61ee287bc -> 75364296c
refs/heads/trunk 8f7678967 -> 047c04611
Fix test built
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/61ee287b
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/61ee287b
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/61ee287b
Branch: refs/heads/trunk
Commit: 61ee287bc7d56008c3b7851f0f2e2413325d81f4
Parents: 8d87e0e
Author: Sylvain Lebresne <sy...@datastax.com>
Authored: Mon Jul 7 18:16:54 2014 +0200
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Mon Jul 7 18:16:54 2014 +0200
----------------------------------------------------------------------
test/unit/org/apache/cassandra/cql3/CQLTester.java | 2 --
1 file changed, 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/61ee287b/test/unit/org/apache/cassandra/cql3/CQLTester.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/CQLTester.java b/test/unit/org/apache/cassandra/cql3/CQLTester.java
index 38aff2b..3363e16 100644
--- a/test/unit/org/apache/cassandra/cql3/CQLTester.java
+++ b/test/unit/org/apache/cassandra/cql3/CQLTester.java
@@ -62,8 +62,6 @@ public abstract class CQLTester
private String currentTable;
private final Set<String> currentTypes = new HashSet<>();
- private final Set<String> currentTypes = new HashSet<>();
-
@BeforeClass
public static void setUpClass() throws Throwable
{
[14/23] git commit: Introduce CQL support for stress tool
Posted by be...@apache.org.
Introduce CQL support for stress tool
patch by Jake Luciani and Benedict Elliott Smith
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/75364296
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/75364296
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/75364296
Branch: refs/heads/trunk
Commit: 75364296cb3749dfa6d4307cf055f1a18bcf7a9b
Parents: 61ee287
Author: Benedict Elliott Smith <be...@apache.org>
Authored: Mon Jul 7 18:03:59 2014 +0100
Committer: Benedict Elliott Smith <be...@apache.org>
Committed: Mon Jul 7 18:25:11 2014 +0100
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../cassandra/thrift/ThriftConversion.java | 19 +
.../org/apache/cassandra/utils/UUIDGen.java | 8 +
tools/bin/cassandra-stress | 2 +-
tools/cqlstress-counter-example.yaml | 85 +++
tools/cqlstress-example.yaml | 99 +++
tools/cqlstress-insanity-example.yaml | 102 +++
.../org/apache/cassandra/stress/Operation.java | 218 +-----
.../apache/cassandra/stress/StressAction.java | 262 +++----
.../apache/cassandra/stress/StressMetrics.java | 17 +-
.../apache/cassandra/stress/StressProfile.java | 504 +++++++++++++
.../org/apache/cassandra/stress/StressYaml.java | 38 +
.../cassandra/stress/generate/Distribution.java | 57 ++
.../generate/DistributionBoundApache.java | 84 +++
.../stress/generate/DistributionFactory.java | 31 +
.../stress/generate/DistributionFixed.java | 54 ++
.../stress/generate/DistributionInverted.java | 37 +
.../generate/DistributionOffsetApache.java | 80 +++
.../cassandra/stress/generate/Partition.java | 343 +++++++++
.../stress/generate/PartitionGenerator.java | 80 +++
.../stress/generate/RatioDistribution.java | 25 +
.../generate/RatioDistributionFactory.java | 31 +
.../apache/cassandra/stress/generate/Row.java | 22 +
.../stress/generate/SeedGenerator.java | 8 +
.../stress/generate/SeedRandomGenerator.java | 33 +
.../stress/generate/SeedSeriesGenerator.java | 21 +
.../stress/generate/values/Booleans.java | 37 +
.../cassandra/stress/generate/values/Bytes.java | 54 ++
.../cassandra/stress/generate/values/Dates.java | 46 ++
.../stress/generate/values/Doubles.java | 37 +
.../stress/generate/values/Floats.java | 37 +
.../stress/generate/values/Generator.java | 50 ++
.../stress/generate/values/GeneratorConfig.java | 68 ++
.../stress/generate/values/HexBytes.java | 56 ++
.../stress/generate/values/HexStrings.java | 55 ++
.../cassandra/stress/generate/values/Inets.java | 57 ++
.../stress/generate/values/Integers.java | 38 +
.../cassandra/stress/generate/values/Lists.java | 55 ++
.../cassandra/stress/generate/values/Longs.java | 37 +
.../cassandra/stress/generate/values/Sets.java | 54 ++
.../stress/generate/values/Strings.java | 49 ++
.../stress/generate/values/TimeUUIDs.java | 51 ++
.../cassandra/stress/generate/values/UUIDs.java | 39 +
.../cassandra/stress/generatedata/DataGen.java | 39 -
.../stress/generatedata/DataGenBytesRandom.java | 45 --
.../stress/generatedata/DataGenFactory.java | 30 -
.../stress/generatedata/DataGenHex.java | 60 --
.../DataGenHexFromDistribution.java | 66 --
.../generatedata/DataGenHexFromOpIndex.java | 48 --
.../generatedata/DataGenStringDictionary.java | 107 ---
.../generatedata/DataGenStringRepeats.java | 90 ---
.../stress/generatedata/Distribution.java | 40 --
.../generatedata/DistributionBoundApache.java | 63 --
.../generatedata/DistributionFactory.java | 31 -
.../stress/generatedata/DistributionFixed.java | 46 --
.../generatedata/DistributionOffsetApache.java | 61 --
.../generatedata/DistributionSeqBatch.java | 68 --
.../cassandra/stress/generatedata/KeyGen.java | 54 --
.../cassandra/stress/generatedata/RowGen.java | 53 --
.../generatedata/RowGenDistributedSize.java | 116 ---
.../stress/operations/CqlCounterAdder.java | 77 --
.../stress/operations/CqlCounterGetter.java | 69 --
.../operations/CqlIndexedRangeSlicer.java | 118 ---
.../stress/operations/CqlInserter.java | 88 ---
.../stress/operations/CqlMultiGetter.java | 42 --
.../stress/operations/CqlOperation.java | 698 ------------------
.../stress/operations/CqlRangeSlicer.java | 59 --
.../cassandra/stress/operations/CqlReader.java | 91 ---
.../stress/operations/FixedOpDistribution.java | 25 +
.../stress/operations/OpDistribution.java | 11 +
.../operations/OpDistributionFactory.java | 12 +
.../operations/SampledOpDistribution.java | 41 ++
.../SampledOpDistributionFactory.java | 72 ++
.../stress/operations/ThriftCounterAdder.java | 95 ---
.../stress/operations/ThriftCounterGetter.java | 68 --
.../operations/ThriftIndexedRangeSlicer.java | 114 ---
.../stress/operations/ThriftInserter.java | 117 ---
.../stress/operations/ThriftMultiGetter.java | 80 ---
.../stress/operations/ThriftRangeSlicer.java | 85 ---
.../stress/operations/ThriftReader.java | 94 ---
.../operations/predefined/CqlCounterAdder.java | 84 +++
.../operations/predefined/CqlCounterGetter.java | 74 ++
.../operations/predefined/CqlInserter.java | 79 ++
.../operations/predefined/CqlOperation.java | 714 +++++++++++++++++++
.../stress/operations/predefined/CqlReader.java | 87 +++
.../predefined/PredefinedOperation.java | 248 +++++++
.../predefined/ThriftCounterAdder.java | 86 +++
.../predefined/ThriftCounterGetter.java | 66 ++
.../operations/predefined/ThriftInserter.java | 96 +++
.../operations/predefined/ThriftReader.java | 79 ++
.../operations/userdefined/SchemaInsert.java | 144 ++++
.../operations/userdefined/SchemaQuery.java | 86 +++
.../operations/userdefined/SchemaStatement.java | 164 +++++
.../cassandra/stress/settings/Command.java | 24 +-
.../stress/settings/CommandCategory.java | 4 +-
.../stress/settings/OptionAnyProbabilities.java | 78 ++
.../stress/settings/OptionDataGen.java | 203 ------
.../stress/settings/OptionDistribution.java | 75 +-
.../settings/OptionEnumProbabilities.java | 62 ++
.../cassandra/stress/settings/OptionMulti.java | 3 +-
.../settings/OptionRatioDistribution.java | 166 +++++
.../cassandra/stress/settings/OptionSimple.java | 5 +-
.../stress/settings/SettingsColumn.java | 50 +-
.../stress/settings/SettingsCommand.java | 58 +-
.../stress/settings/SettingsCommandMixed.java | 207 ------
.../settings/SettingsCommandPreDefined.java | 145 ++++
.../SettingsCommandPreDefinedMixed.java | 151 ++++
.../stress/settings/SettingsCommandUser.java | 135 ++++
.../cassandra/stress/settings/SettingsKey.java | 27 +-
.../cassandra/stress/settings/SettingsMisc.java | 2 +-
.../cassandra/stress/settings/SettingsMode.java | 6 +-
.../stress/settings/SettingsSchema.java | 77 +-
.../stress/settings/SettingsTransport.java | 2 +-
.../stress/settings/StressSettings.java | 36 +-
.../stress/settings/ValidationType.java | 8 +
.../cassandra/stress/util/JavaDriverClient.java | 19 +-
.../stress/util/SmartThriftClient.java | 4 +-
.../org/apache/cassandra/stress/util/Timer.java | 17 +-
.../cassandra/stress/util/TimingInterval.java | 26 +-
119 files changed, 5861 insertions(+), 3890 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 491ad6d..ff2f586 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
2.1.0-rc3
+ * Introduce CQL support for stress tool (CASSANDRA-6146)
* Fix ClassCastException processing expired messages (CASSANDRA-7496)
* Fix prepared marker for collections inside UDT (CASSANDRA-7472)
* Remove left-over populate_io_cache_on_flush and replicate_on_write
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/src/java/org/apache/cassandra/thrift/ThriftConversion.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/thrift/ThriftConversion.java b/src/java/org/apache/cassandra/thrift/ThriftConversion.java
index 9573b56..0c75d2c 100644
--- a/src/java/org/apache/cassandra/thrift/ThriftConversion.java
+++ b/src/java/org/apache/cassandra/thrift/ThriftConversion.java
@@ -51,6 +51,25 @@ public class ThriftConversion
throw new AssertionError();
}
+ public static ConsistencyLevel toThrift(org.apache.cassandra.db.ConsistencyLevel cl)
+ {
+ switch (cl)
+ {
+ case ANY: return ConsistencyLevel.ANY;
+ case ONE: return ConsistencyLevel.ONE;
+ case TWO: return ConsistencyLevel.TWO;
+ case THREE: return ConsistencyLevel.THREE;
+ case QUORUM: return ConsistencyLevel.QUORUM;
+ case ALL: return ConsistencyLevel.ALL;
+ case LOCAL_QUORUM: return ConsistencyLevel.LOCAL_QUORUM;
+ case EACH_QUORUM: return ConsistencyLevel.EACH_QUORUM;
+ case SERIAL: return ConsistencyLevel.SERIAL;
+ case LOCAL_SERIAL: return ConsistencyLevel.LOCAL_SERIAL;
+ case LOCAL_ONE: return ConsistencyLevel.LOCAL_ONE;
+ }
+ throw new AssertionError();
+ }
+
// We never return, but returning a RuntimeException allows to write "throw rethrow(e)" without java complaining
// for methods that have a return value.
public static RuntimeException rethrow(RequestExecutionException e) throws UnavailableException, TimedOutException
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/src/java/org/apache/cassandra/utils/UUIDGen.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/utils/UUIDGen.java b/src/java/org/apache/cassandra/utils/UUIDGen.java
index f385744..53293b2 100644
--- a/src/java/org/apache/cassandra/utils/UUIDGen.java
+++ b/src/java/org/apache/cassandra/utils/UUIDGen.java
@@ -25,6 +25,8 @@ import java.util.Collection;
import java.util.Random;
import java.util.UUID;
+import com.google.common.annotations.VisibleForTesting;
+
/**
* The goods are here: www.ietf.org/rfc/rfc4122.txt.
@@ -80,6 +82,12 @@ public class UUIDGen
return new UUID(createTime(fromUnixTimestamp(when)), clockSeqAndNode);
}
+ @VisibleForTesting
+ public static UUID getTimeUUID(long when, long clockSeqAndNode)
+ {
+ return new UUID(createTime(fromUnixTimestamp(when)), clockSeqAndNode);
+ }
+
/** creates a type 1 uuid from raw bytes. */
public static UUID getUUID(ByteBuffer raw)
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/bin/cassandra-stress
----------------------------------------------------------------------
diff --git a/tools/bin/cassandra-stress b/tools/bin/cassandra-stress
index 39257cd..c855cf5 100755
--- a/tools/bin/cassandra-stress
+++ b/tools/bin/cassandra-stress
@@ -42,4 +42,4 @@ if [ "x$JAVA" = "x" ]; then
exit 1
fi
-$JAVA -server -cp $CLASSPATH org.apache.cassandra.stress.Stress $@
+$JAVA -server -ea -cp $CLASSPATH org.apache.cassandra.stress.Stress $@
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/cqlstress-counter-example.yaml
----------------------------------------------------------------------
diff --git a/tools/cqlstress-counter-example.yaml b/tools/cqlstress-counter-example.yaml
new file mode 100644
index 0000000..a65080a
--- /dev/null
+++ b/tools/cqlstress-counter-example.yaml
@@ -0,0 +1,85 @@
+#
+# This is an example YAML profile for cassandra-stress
+#
+# insert data
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1)
+#
+# read, using query simple1:
+# cassandra-stress profile=/home/jake/stress1.yaml ops(simple1=1)
+#
+# mixed workload (90/10)
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1,simple1=9)
+
+
+#
+# Keyspace info
+#
+keyspace: stresscql
+
+#
+# The CQL for creating a keyspace (optional if it already exists)
+#
+keyspace_definition: |
+ CREATE KEYSPACE stresscql WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
+
+#
+# Table info
+#
+table: counttest
+
+#
+# The CQL for creating a table you wish to stress (optional if it already exists)
+#
+table_definition: |
+ CREATE TABLE counttest (
+ name text PRIMARY KEY,
+ count counter
+ ) WITH comment='A table of many types to test wide rows'
+
+#
+# Optional meta information on the generated columns in the above table
+# The min and max only apply to text and blob types
+# The distribution field represents the total unique population
+# distribution of that column across rows. Supported types are
+#
+# EXP(min..max) An exponential distribution over the range [min..max]
+# EXTREME(min..max,shape) An extreme value (Weibull) distribution over the range [min..max]
+# GAUSSIAN(min..max,stdvrng) A gaussian/normal distribution, where mean=(min+max)/2, and stdev is (mean-min)/stdvrng
+# GAUSSIAN(min..max,mean,stdev) A gaussian/normal distribution, with explicitly defined mean and stdev
+# UNIFORM(min..max) A uniform distribution over the range [min, max]
+# FIXED(val) A fixed distribution, always returning the same value
+# Aliases: extr, gauss, normal, norm, weibull
+#
+# If preceded by ~, the distribution is inverted
+#
+# Defaults for all columns are size: uniform(1..256), identity: uniform(1..1024)
+#
+
+columnspec:
+ - name: name
+ clustering: uniform(1..100)
+ size: uniform(1..4)
+ - name: count
+ population: fixed(1)
+
+insert:
+ partitions: fixed(1) # number of unique partitions to update in a single operation
+ # if perbatch < 1, multiple batches will be used but all partitions will
+ # occur in all batches (unless already finished); only the row counts will vary
+ pervisit: fixed(1)/1 # ratio of rows each partition should update in a single visit to the partition,
+ # as a proportion of the total possible for the partition
+ perbatch: fixed(1)/1 # number of rows each partition should update in a single batch statement,
+ # as a proportion of the proportion we are inserting this visit
+ # (i.e. compounds with (and capped by) pervisit)
+ batchtype: UNLOGGED # type of batch to use
+
+#
+# A list of queries you wish to run against the schema
+#
+queries:
+ simple1: select * from counttest where name = ?
+
+#
+# In order to generate data consistently we need something to generate a unique key for this schema profile.
+#
+seed: changing this string changes the generated data. its hashcode is used as the random seed.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/cqlstress-example.yaml
----------------------------------------------------------------------
diff --git a/tools/cqlstress-example.yaml b/tools/cqlstress-example.yaml
new file mode 100644
index 0000000..a997529
--- /dev/null
+++ b/tools/cqlstress-example.yaml
@@ -0,0 +1,99 @@
+#
+# This is an example YAML profile for cassandra-stress
+#
+# insert data
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1)
+#
+# read, using query simple1:
+# cassandra-stress profile=/home/jake/stress1.yaml ops(simple1=1)
+#
+# mixed workload (90/10)
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1,simple1=9)
+
+
+#
+# Keyspace info
+#
+keyspace: stresscql
+
+#
+# The CQL for creating a keyspace (optional if it already exists)
+#
+keyspace_definition: |
+ CREATE KEYSPACE stresscql WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
+
+#
+# Table info
+#
+table: typestest
+
+#
+# The CQL for creating a table you wish to stress (optional if it already exists)
+#
+table_definition: |
+ CREATE TABLE typestest (
+ name text,
+ choice boolean,
+ date timestamp,
+ address inet,
+ dbl double,
+ lval bigint,
+ ival int,
+ uid timeuuid,
+ value blob,
+ PRIMARY KEY((name,choice), date, address, dbl, lval, ival, uid)
+ ) WITH COMPACT STORAGE
+ AND compaction = { 'class':'LeveledCompactionStrategy' }
+ AND comment='A table of many types to test wide rows'
+
+#
+# Optional meta information on the generated columns in the above table
+# The min and max only apply to text and blob types
+# The distribution field represents the total unique population
+# distribution of that column across rows. Supported types are
+#
+# EXP(min..max) An exponential distribution over the range [min..max]
+# EXTREME(min..max,shape) An extreme value (Weibull) distribution over the range [min..max]
+# GAUSSIAN(min..max,stdvrng) A gaussian/normal distribution, where mean=(min+max)/2, and stdev is (mean-min)/stdvrng
+# GAUSSIAN(min..max,mean,stdev) A gaussian/normal distribution, with explicitly defined mean and stdev
+# UNIFORM(min..max) A uniform distribution over the range [min, max]
+# FIXED(val) A fixed distribution, always returning the same value
+# Aliases: extr, gauss, normal, norm, weibull
+#
+# If preceded by ~, the distribution is inverted
+#
+# Defaults for all columns are size: uniform(1..256), identity: uniform(1..1024)
+#
+columnspec:
+ - name: name
+ size: uniform(1..10)
+ population: uniform(1..1M) # the range of unique values to select for the field (default is 100Billion)
+ - name: choice
+ - name: date
+ cluster: uniform(1..4)
+ - name: lval
+ population: gaussian(1..1000)
+ cluster: uniform(1..4)
+
+insert:
+ partitions: uniform(1..50) # number of unique partitions to update in a single operation
+ # if perbatch < 1, multiple batches will be used but all partitions will
+ # occur in all batches (unless already finished); only the row counts will vary
+ pervisit: uniform(1..10)/10 # ratio of rows each partition should update in a single visit to the partition,
+ # as a proportion of the total possible for the partition
+ perbatch: ~exp(1..3)/4 # number of rows each partition should update in a single batch statement,
+ # as a proportion of the proportion we are inserting this visit
+ # (i.e. compounds with (and capped by) pervisit)
+ batchtype: UNLOGGED # type of batch to use
+
+#
+# A list of queries you wish to run against the schema
+#
+queries:
+ simple1: select * from typestest where name = ? and choice = ? LIMIT 100
+ range1: select * from typestest where name = ? and choice = ? and date >= ? LIMIT 100
+
+#
+# In order to generate data consistently we need something to generate a unique key for this schema profile.
+#
+seed: changing this string changes the generated data. its hashcode is used as the random seed.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/cqlstress-insanity-example.yaml
----------------------------------------------------------------------
diff --git a/tools/cqlstress-insanity-example.yaml b/tools/cqlstress-insanity-example.yaml
new file mode 100644
index 0000000..e94c9c3
--- /dev/null
+++ b/tools/cqlstress-insanity-example.yaml
@@ -0,0 +1,102 @@
+#
+# This is an example YAML profile for cassandra-stress
+#
+# insert data
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1)
+#
+# read, using query simple1:
+# cassandra-stress profile=/home/jake/stress1.yaml ops(simple1=1)
+#
+# mixed workload (90/10)
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1,simple1=9)
+
+
+#
+# Keyspace info
+#
+keyspace: stresscql
+
+#
+# The CQL for creating a keyspace (optional if it already exists)
+#
+keyspace_definition: |
+ CREATE KEYSPACE stresscql WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
+
+#
+# Table info
+#
+table: insanitytest
+
+#
+# The CQL for creating a table you wish to stress (optional if it already exists)
+#
+table_definition: |
+ CREATE TABLE insanitytest (
+ name text,
+ choice boolean,
+ date timestamp,
+ address inet,
+ dbl double,
+ lval bigint,
+ fval float,
+ ival int,
+ uid timeuuid,
+ dates list<timestamp>,
+ inets set<inet>,
+ value blob,
+ PRIMARY KEY((name, choice), date)
+ ) WITH compaction = { 'class':'LeveledCompactionStrategy' }
+ AND comment='A table of many types to test wide rows and collections'
+
+#
+# Optional meta information on the generated columns in the above table
+# The min and max only apply to text and blob types
+# The distribution field represents the total unique population
+# distribution of that column across rows. Supported types are
+#
+# EXP(min..max) An exponential distribution over the range [min..max]
+# EXTREME(min..max,shape) An extreme value (Weibull) distribution over the range [min..max]
+# GAUSSIAN(min..max,stdvrng) A gaussian/normal distribution, where mean=(min+max)/2, and stdev is (mean-min)/stdvrng
+# GAUSSIAN(min..max,mean,stdev) A gaussian/normal distribution, with explicitly defined mean and stdev
+# UNIFORM(min..max) A uniform distribution over the range [min, max]
+# FIXED(val) A fixed distribution, always returning the same value
+# Aliases: extr, gauss, normal, norm, weibull
+#
+# If preceded by ~, the distribution is inverted
+#
+# Defaults for all columns are size: uniform(1..256), population: uniform(1..100B)
+#
+columnspec:
+ - name: name
+ clustering: uniform(1..4)
+ - name: date
+ clustering: gaussian(1..20)
+ - name: lval
+ population: fixed(1)
+ - name: dates
+ clustering: uniform(1..100)
+ - name: inets
+ clustering: uniform(1..200)
+ - name: value
+
+insert:
+ partitions: fixed(1) # number of unique partitions to update in a single operation
+ # if perbatch < 1, multiple batches will be used but all partitions will
+ # occur in all batches (unless already finished); only the row counts will vary
+ pervisit: uniform(1..10)/100K # ratio of rows each partition should update in a single visit to the partition,
+ # as a proportion of the total possible for the partition
+ perbatch: fixed(1)/1 # number of rows each partition should update in a single batch statement,
+ # as a proportion of the proportion we are inserting this visit
+ # (i.e. compounds with (and capped by) pervisit)
+ batchtype: UNLOGGED # type of batch to use
+
+#
+# A list of queries you wish to run against the schema
+#
+queries:
+ simple1: select * from insanitytest where name = ? and choice = ? LIMIT 100
+
+#
+# In order to generate data consistently we need something to generate a unique key for this schema profile.
+#
+seed: changing this string changes the generated data. its hashcode is used as the random seed.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/Operation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/Operation.java b/tools/stress/src/org/apache/cassandra/stress/Operation.java
index 87afb3d..7831074 100644
--- a/tools/stress/src/org/apache/cassandra/stress/Operation.java
+++ b/tools/stress/src/org/apache/cassandra/stress/Operation.java
@@ -18,203 +18,47 @@
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.generate.Distribution;
+import org.apache.cassandra.stress.generate.Partition;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
import org.apache.cassandra.stress.settings.*;
import org.apache.cassandra.stress.util.JavaDriverClient;
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;
public abstract class Operation
{
- public final long index;
- protected final State state;
+ public final StressSettings settings;
+ public final Timer timer;
+ public final PartitionGenerator generator;
+ public final Distribution partitionCount;
- public Operation(State state, long idx)
+ protected List<Partition> partitions;
+
+ public Operation(Timer timer, PartitionGenerator generator, StressSettings settings, Distribution partitionCount)
{
- index = idx;
- this.state = state;
+ this.generator = generator;
+ this.timer = timer;
+ this.settings = settings;
+ this.partitionCount = partitionCount;
}
public static interface RunOp
{
public boolean run() throws Exception;
- public String key();
- public int keyCount();
+ public int partitionCount();
+ public int rowCount();
}
- // one per thread!
- public static final class State
+ protected void setPartitions(List<Partition> partitions)
{
-
- public final StressSettings settings;
- public final Timer timer;
- public final Command type;
- public final KeyGen keyGen;
- public final RowGen rowGen;
- public final Distribution counteradd;
- public final List<ColumnParent> columnParents;
- public final StressMetrics metrics;
- public final SettingsCommandMixed.CommandSelector commandSelector;
- private final EnumMap<Command, State> substates;
- private Object cqlCache;
-
- public State(Command type, StressSettings settings, StressMetrics metrics)
- {
- this.type = type;
- this.timer = metrics.getTiming().newTimer();
- if (type == Command.MIXED)
- {
- commandSelector = ((SettingsCommandMixed) settings.command).selector();
- substates = new EnumMap<>(Command.class);
- }
- else
- {
- 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;
- this.columnParents = columnParents(type, settings);
- }
-
- private State(Command type, State copy)
- {
- this.type = type;
- this.timer = copy.timer;
- this.rowGen = copy.rowGen;
- this.keyGen = copy.keyGen;
- 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<ColumnParent> 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;
- }
- public boolean isCql2()
- {
- return settings.mode.cqlVersion == CqlVersion.CQL2;
- }
- public Object getCqlCache()
- {
- return cqlCache;
- }
- public void storeCqlCache(Object val)
- {
- cqlCache = val;
- }
-
- public State substate(Command command)
- {
- assert type == Command.MIXED;
- State substate = substates.get(command);
- if (substate == null)
- {
- substates.put(command, substate = new State(command, this));
- }
- return substate;
- }
-
- }
-
- protected ByteBuffer getKey()
- {
- return state.keyGen.getKeys(1, index).get(0);
- }
-
- protected List<ByteBuffer> getKeys(int count)
- {
- return state.keyGen.getKeys(count, index);
- }
-
- protected List<ByteBuffer> generateColumnValues(ByteBuffer key)
- {
- 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<ByteBuffer> randomNames()
- {
- int count = state.rowGen.count(index);
- List<ByteBuffer> src = state.settings.columns.names;
- if (count == src.size())
- return src;
- ThreadLocalRandom rnd = ThreadLocalRandom.current();
- List<ByteBuffer> 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;
+ this.partitions = partitions;
}
/**
@@ -234,13 +78,13 @@ public abstract class Operation
public void timeWithRetry(RunOp run) throws IOException
{
- state.timer.start();
+ timer.start();
boolean success = false;
String exceptionMessage = null;
int tries = 0;
- for (; tries < state.settings.command.tries; tries++)
+ for (; tries < settings.command.tries; tries++)
{
try
{
@@ -249,7 +93,7 @@ public abstract class Operation
}
catch (Exception e)
{
- switch (state.settings.log.level)
+ switch (settings.log.level)
{
case MINIMAL:
break;
@@ -269,15 +113,13 @@ public abstract class Operation
}
}
- state.timer.stop(run.keyCount());
+ timer.stop(run.partitionCount(), run.rowCount());
if (!success)
{
- error(String.format("Operation [%d] x%d key %s (0x%s) %s%n",
- index,
+ error(String.format("Operation x%d on key(s) %s: %s%n",
tries,
- run.key(),
- ByteBufferUtil.bytesToHex(ByteBufferUtil.bytes(run.key())),
+ key(),
(exceptionMessage == null)
? "Data returned was not validated"
: "Error executing: " + exceptionMessage));
@@ -285,6 +127,14 @@ public abstract class Operation
}
+ private String key()
+ {
+ List<String> keys = new ArrayList<>();
+ for (Partition partition : partitions)
+ keys.add(partition.getKeyAsString());
+ return keys.toString();
+ }
+
protected String getExceptionMessage(Exception e)
{
String className = e.getClass().getSimpleName();
@@ -294,9 +144,9 @@ public abstract class Operation
protected void error(String message) throws IOException
{
- if (!state.settings.command.ignoreErrors)
+ if (!settings.command.ignoreErrors)
throw new IOException(message);
- else if (state.settings.log.level.compareTo(SettingsLog.Level.MINIMAL) > 0)
+ else if (settings.log.level.compareTo(SettingsLog.Level.MINIMAL) > 0)
System.err.println(message);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/StressAction.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressAction.java b/tools/stress/src/org/apache/cassandra/stress/StressAction.java
index 07ba1d8..2105a72 100644
--- a/tools/stress/src/org/apache/cassandra/stress/StressAction.java
+++ b/tools/stress/src/org/apache/cassandra/stress/StressAction.java
@@ -21,6 +21,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
@@ -29,10 +30,15 @@ import java.util.concurrent.atomic.AtomicLong;
import com.google.common.util.concurrent.RateLimiter;
import com.google.common.util.concurrent.Uninterruptibles;
-import org.apache.cassandra.stress.operations.*;
+
+import org.apache.cassandra.stress.generate.Partition;
+import org.apache.cassandra.stress.generate.SeedGenerator;
+import org.apache.cassandra.stress.operations.OpDistribution;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
import org.apache.cassandra.stress.settings.*;
import org.apache.cassandra.stress.util.JavaDriverClient;
import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
import org.apache.cassandra.transport.SimpleClient;
public class StressAction implements Runnable
@@ -52,7 +58,8 @@ public class StressAction implements Runnable
// creating keyspace and column families
settings.maybeCreateKeyspaces();
- warmup(settings.command.type, settings.command);
+ if (!settings.command.noWarmup)
+ warmup(settings.command.getFactory(settings));
output.println("Sleeping 2s...");
Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
@@ -61,7 +68,7 @@ public class StressAction implements Runnable
if (settings.rate.auto)
success = runAuto();
else
- success = null != run(settings.command.type, settings.rate.threadCount, settings.command.count, output);
+ success = null != run(settings.command.getFactory(settings), settings.rate.threadCount, settings.command.count, output);
if (success)
output.println("END");
@@ -72,33 +79,18 @@ public class StressAction implements Runnable
}
// type provided separately to support recursive call for mixed command with each command type it is performing
- private void warmup(Command type, SettingsCommand command)
+ private void warmup(OpDistributionFactory operations)
{
// warmup - do 50k iterations; by default hotspot compiles methods after 10k invocations
PrintStream warmupOutput = new PrintStream(new OutputStream() { @Override public void write(int b) throws IOException { } } );
- int iterations;
- switch (type.category)
+ int iterations = 50000 * settings.node.nodes.size();
+ for (OpDistributionFactory single : operations.each())
{
- case BASIC:
- iterations = 50000;
- break;
- case MIXED:
- for (Command subtype : ((SettingsCommandMixed) command).getCommands())
- warmup(subtype, command);
- return;
- case MULTI:
- int keysAtOnce = command.keysAtOnce;
- iterations = Math.min(50000, (int) Math.ceil(500000d / keysAtOnce));
- break;
- default:
- throw new IllegalStateException();
+ // we need to warm up all the nodes in the cluster ideally, but we may not be the only stress instance;
+ // so warm up all the nodes we're speaking to only.
+ output.println(String.format("Warming up %s with %d iterations...", single.desc(), iterations));
+ run(single, 20, iterations, warmupOutput);
}
-
- // we need to warm up all the nodes in the cluster ideally, but we may not be the only stress instance;
- // so warm up all the nodes we're speaking to only.
- iterations *= settings.node.nodes.size();
- output.println(String.format("Warming up %s with %d iterations...", type, iterations));
- run(type, 20, iterations, warmupOutput);
}
// TODO : permit varying more than just thread count
@@ -113,7 +105,7 @@ public class StressAction implements Runnable
{
output.println(String.format("Running with %d threadCount", threadCount));
- StressMetrics result = run(settings.command.type, threadCount, settings.command.count, output);
+ StressMetrics result = run(settings.command.getFactory(settings), threadCount, settings.command.count, output);
if (result == null)
return false;
results.add(result);
@@ -170,13 +162,13 @@ public class StressAction implements Runnable
return improvement / count;
}
- private StressMetrics run(Command type, int threadCount, long opCount, PrintStream output)
+ private StressMetrics run(OpDistributionFactory operations, int threadCount, long opCount, PrintStream output)
{
output.println(String.format("Running %s with %d threads %s",
- type.toString(),
- threadCount,
- opCount > 0 ? " for " + opCount + " iterations" : "until stderr of mean < " + settings.command.targetUncertainty));
+ operations.desc(),
+ threadCount,
+ opCount > 0 ? " for " + opCount + " iterations" : "until stderr of mean < " + settings.command.targetUncertainty));
final WorkQueue workQueue;
if (opCount < 0)
workQueue = new ContinuousWorkQueue(50);
@@ -193,7 +185,7 @@ public class StressAction implements Runnable
final CountDownLatch done = new CountDownLatch(threadCount);
final Consumer[] consumers = new Consumer[threadCount];
for (int i = 0; i < threadCount; i++)
- consumers[i] = new Consumer(type, done, workQueue, metrics, rateLimiter);
+ consumers[i] = new Consumer(operations, done, workQueue, metrics, rateLimiter);
// starting worker threadCount
for (int i = 0; i < threadCount; i++)
@@ -236,18 +228,24 @@ public class StressAction implements Runnable
private class Consumer extends Thread
{
- private final Operation.State state;
+ private final OpDistribution operations;
+ private final StressMetrics metrics;
+ private final Timer timer;
+ private final SeedGenerator seedGenerator;
private final RateLimiter rateLimiter;
private volatile boolean success = true;
private final WorkQueue workQueue;
private final CountDownLatch done;
- public Consumer(Command type, CountDownLatch done, WorkQueue workQueue, StressMetrics metrics, RateLimiter rateLimiter)
+ public Consumer(OpDistributionFactory operations, CountDownLatch done, WorkQueue workQueue, StressMetrics metrics, RateLimiter rateLimiter)
{
this.done = done;
this.rateLimiter = rateLimiter;
this.workQueue = workQueue;
- this.state = new Operation.State(type, settings, metrics);
+ this.metrics = metrics;
+ this.timer = metrics.getTiming().newTimer();
+ this.seedGenerator = settings.keys.newSeedGenerator();
+ this.operations = operations.get(timer);
}
public void run()
@@ -269,63 +267,89 @@ public class StressAction implements Runnable
sclient = settings.getSimpleNativeClient();
break;
case THRIFT:
- tclient = settings.getThriftClient();
- break;
case THRIFT_SMART:
- tclient = settings.getSmartThriftClient();
+ tclient = settings.getThriftClient();
break;
default:
throw new IllegalStateException();
}
- Work work;
- while ( null != (work = workQueue.poll()) )
+ int maxBatchSize = operations.maxBatchSize();
+ Work work = workQueue.poll();
+ Partition[] partitions = new Partition[maxBatchSize];
+ int workDone = 0;
+ while (work != null)
{
- if (rateLimiter != null)
- rateLimiter.acquire(work.count);
+ Operation op = operations.next();
+ op.generator.reset();
+ int batchSize = Math.max(1, (int) op.partitionCount.next());
+ int partitionCount = 0;
- for (int i = 0 ; i < work.count ; i++)
+ while (partitionCount < batchSize)
{
- try
+ int count = Math.min((work.count - workDone), batchSize - partitionCount);
+ for (int i = 0 ; i < count ; i++)
{
- Operation op = createOperation(state, i + work.offset);
- switch (settings.mode.api)
- {
- case JAVA_DRIVER_NATIVE:
- op.run(jclient);
- break;
- case SIMPLE_NATIVE:
- op.run(sclient);
- break;
- case THRIFT:
- case THRIFT_SMART:
- default:
- op.run(tclient);
- }
- } catch (Exception e)
+ long seed = seedGenerator.next(work.offset + workDone + i);
+ partitions[partitionCount + i] = op.generator.generate(seed);
+ }
+ workDone += count;
+ partitionCount += count;
+ if (workDone == work.count)
{
- if (output == null)
+ workDone = 0;
+ work = workQueue.poll();
+ if (work == null)
{
- System.err.println(e.getMessage());
- success = false;
- System.exit(-1);
+ if (partitionCount == 0)
+ return;
+ break;
}
+ if (rateLimiter != null)
+ rateLimiter.acquire(work.count);
+ }
+ }
+
+ op.setPartitions(Arrays.asList(partitions).subList(0, partitionCount));
- e.printStackTrace(output);
+ try
+ {
+ switch (settings.mode.api)
+ {
+ case JAVA_DRIVER_NATIVE:
+ op.run(jclient);
+ break;
+ case SIMPLE_NATIVE:
+ op.run(sclient);
+ break;
+ case THRIFT:
+ case THRIFT_SMART:
+ default:
+ op.run(tclient);
+ }
+ }
+ catch (Exception e)
+ {
+ if (output == null)
+ {
+ System.err.println(e.getMessage());
success = false;
- workQueue.stop();
- state.metrics.cancel();
- return;
+ System.exit(-1);
}
+
+ e.printStackTrace(output);
+ success = false;
+ workQueue.stop();
+ metrics.cancel();
+ return;
}
}
-
}
finally
{
done.countDown();
- state.timer.close();
+ timer.close();
}
}
@@ -443,106 +467,4 @@ public class StressAction implements Runnable
}
- private Operation createOperation(Operation.State state, long index)
- {
- return createOperation(state.type, state, index);
- }
- private Operation createOperation(Command type, Operation.State state, long index)
- {
- switch (type)
- {
- case READ:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftReader(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlReader(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
-
- case COUNTER_READ:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftCounterGetter(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlCounterGetter(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case WRITE:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftInserter(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlInserter(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case COUNTER_WRITE:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftCounterAdder(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlCounterAdder(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case RANGE_SLICE:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftRangeSlicer(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlRangeSlicer(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case INDEXED_RANGE_SLICE:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftIndexedRangeSlicer(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlIndexedRangeSlicer(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case READ_MULTI:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftMultiGetter(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlMultiGetter(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case MIXED:
- Command subcommand = state.commandSelector.next();
- return createOperation(subcommand, state.substate(subcommand), index);
-
- }
-
- throw new UnsupportedOperationException();
- }
-
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java b/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
index 54a1e2c..7e5c1b6 100644
--- a/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
+++ b/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
@@ -127,20 +127,21 @@ public class StressMetrics
// PRINT FORMATTING
- public static final String HEADFORMAT = "%-10s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%7s,%9s";
- public static final String ROWFORMAT = "%-10d,%8.0f,%8.0f,%8.1f,%8.1f,%8.1f,%8.1f,%8.1f,%8.1f,%7.1f,%9.5f";
+ public static final String HEADFORMAT = "%-10s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%7s,%9s";
+ public static final String ROWFORMAT = "%-10d,%8.0f,%8.0f,%8.0f,%8.1f,%8.1f,%8.1f,%8.1f,%8.1f,%8.1f,%7.1f,%9.5f";
private static void printHeader(String prefix, PrintStream output)
{
- output.println(prefix + String.format(HEADFORMAT, "ops","op/s", "key/s","mean","med",".95",".99",".999","max","time","stderr"));
+ output.println(prefix + String.format(HEADFORMAT, "partitions","op/s", "pk/s", "row/s","mean","med",".95",".99",".999","max","time","stderr"));
}
private static void printRow(String prefix, TimingInterval interval, TimingInterval total, Uncertainty opRateUncertainty, PrintStream output)
{
output.println(prefix + String.format(ROWFORMAT,
- total.operationCount,
+ total.partitionCount,
interval.realOpRate(),
- interval.keyRate(),
+ interval.partitionRate(),
+ interval.rowRate(),
interval.meanLatency(),
interval.medianLatency(),
interval.rankLatency(0.95f),
@@ -156,9 +157,9 @@ public class StressMetrics
output.println("\n");
output.println("Results:");
TimingInterval history = timing.getHistory();
- output.println(String.format("real op rate : %.0f", history.realOpRate()));
- output.println(String.format("adjusted op rate stderr : %.0f", opRateUncertainty.getUncertainty()));
- output.println(String.format("key rate : %.0f", history.keyRate()));
+ output.println(String.format("op rate : %.0f", history.realOpRate()));
+ output.println(String.format("partition rate : %.0f", history.partitionRate()));
+ output.println(String.format("row rate : %.0f", history.rowRate()));
output.println(String.format("latency mean : %.1f", history.meanLatency()));
output.println(String.format("latency median : %.1f", history.medianLatency()));
output.println(String.format("latency 95th percentile : %.1f", history.rankLatency(.95f)));
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressProfile.java b/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
new file mode 100644
index 0000000..13f26a2
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
@@ -0,0 +1,504 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress;
+
+
+import com.datastax.driver.core.*;
+import com.datastax.driver.core.exceptions.AlreadyExistsException;
+
+import com.google.common.util.concurrent.Uninterruptibles;
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.cql3.QueryProcessor;
+import org.apache.cassandra.cql3.statements.CreateKeyspaceStatement;
+import org.apache.cassandra.exceptions.RequestValidationException;
+
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.RatioDistributionFactory;
+import org.apache.cassandra.stress.generate.values.Booleans;
+import org.apache.cassandra.stress.generate.values.Bytes;
+import org.apache.cassandra.stress.generate.values.Generator;
+import org.apache.cassandra.stress.generate.values.Dates;
+import org.apache.cassandra.stress.generate.values.Doubles;
+import org.apache.cassandra.stress.generate.values.Floats;
+import org.apache.cassandra.stress.generate.values.GeneratorConfig;
+import org.apache.cassandra.stress.generate.values.Inets;
+import org.apache.cassandra.stress.generate.values.Integers;
+import org.apache.cassandra.stress.generate.values.Lists;
+import org.apache.cassandra.stress.generate.values.Longs;
+import org.apache.cassandra.stress.generate.values.Sets;
+import org.apache.cassandra.stress.generate.values.Strings;
+import org.apache.cassandra.stress.generate.values.TimeUUIDs;
+import org.apache.cassandra.stress.generate.values.UUIDs;
+import org.apache.cassandra.stress.operations.userdefined.SchemaInsert;
+import org.apache.cassandra.stress.operations.userdefined.SchemaQuery;
+import org.apache.cassandra.stress.settings.OptionDistribution;
+import org.apache.cassandra.stress.settings.OptionRatioDistribution;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.settings.ValidationType;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.Compression;
+import org.apache.cassandra.thrift.ThriftConversion;
+import org.apache.thrift.TException;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.error.YAMLException;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.Serializable;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+public class StressProfile implements Serializable
+{
+ private String keyspaceCql;
+ private String tableCql;
+ private String seedStr;
+
+ public String keyspaceName;
+ public String tableName;
+ private Map<String, GeneratorConfig> columnConfigs;
+ private Map<String, String> queries;
+ private Map<String, String> insert;
+
+ transient volatile TableMetadata tableMetaData;
+
+ transient volatile GeneratorFactory generatorFactory;
+
+ transient volatile BatchStatement.Type batchType;
+ transient volatile DistributionFactory partitions;
+ transient volatile RatioDistributionFactory pervisit;
+ transient volatile RatioDistributionFactory perbatch;
+ transient volatile PreparedStatement insertStatement;
+ transient volatile Integer thriftInsertId;
+
+ transient volatile Map<String, PreparedStatement> queryStatements;
+ transient volatile Map<String, Integer> thriftQueryIds;
+
+ private void init(StressYaml yaml) throws RequestValidationException
+ {
+ keyspaceName = yaml.keyspace;
+ keyspaceCql = yaml.keyspace_definition;
+ tableName = yaml.table;
+ tableCql = yaml.table_definition;
+ seedStr = yaml.seed;
+ queries = yaml.queries;
+ insert = yaml.insert;
+
+ assert keyspaceName != null : "keyspace name is required in yaml file";
+ assert tableName != null : "table name is required in yaml file";
+ assert queries != null : "queries map is required in yaml file";
+
+ if (keyspaceCql != null && keyspaceCql.length() > 0)
+ {
+ String name = ((CreateKeyspaceStatement) QueryProcessor.parseStatement(keyspaceCql)).keyspace();
+ assert name.equalsIgnoreCase(keyspaceName) : "Name in keyspace_definition doesn't match keyspace property: '" + name + "' != '" + keyspaceName + "'";
+ }
+ else
+ {
+ keyspaceCql = null;
+ }
+
+ if (tableCql != null && tableCql.length() > 0)
+ {
+ String name = CFMetaData.compile(tableCql, keyspaceName).cfName;
+ assert name.equalsIgnoreCase(tableName) : "Name in table_definition doesn't match table property: '" + name + "' != '" + tableName + "'";
+ }
+ else
+ {
+ tableCql = null;
+ }
+
+ columnConfigs = new HashMap<>();
+ for (Map<String,Object> spec : yaml.columnspec)
+ {
+ lowerCase(spec);
+ String name = (String) spec.remove("name");
+ DistributionFactory population = !spec.containsKey("population") ? null : OptionDistribution.get((String) spec.remove("population"));
+ DistributionFactory size = !spec.containsKey("size") ? null : OptionDistribution.get((String) spec.remove("size"));
+ DistributionFactory clustering = !spec.containsKey("cluster") ? null : OptionDistribution.get((String) spec.remove("cluster"));
+
+ if (!spec.isEmpty())
+ throw new IllegalArgumentException("Unrecognised option(s) in column spec: " + spec);
+ if (name == null)
+ throw new IllegalArgumentException("Missing name argument in column spec");
+
+ GeneratorConfig config = new GeneratorConfig(yaml.seed + name, clustering, size, population);
+ columnConfigs.put(name, config);
+ }
+ }
+
+ public void maybeCreateSchema(StressSettings settings)
+ {
+ JavaDriverClient client = settings.getJavaDriverClient(false);
+
+ if (keyspaceCql != null)
+ {
+ try
+ {
+ client.execute(keyspaceCql, org.apache.cassandra.db.ConsistencyLevel.ONE);
+ }
+ catch (AlreadyExistsException e)
+ {
+ }
+ }
+
+ client.execute("use "+keyspaceName, org.apache.cassandra.db.ConsistencyLevel.ONE);
+
+ if (tableCql != null)
+ {
+ try
+ {
+ client.execute(tableCql, org.apache.cassandra.db.ConsistencyLevel.ONE);
+ }
+ catch (AlreadyExistsException e)
+ {
+ }
+
+ System.out.println(String.format("Created schema. Sleeping %ss for propagation.", settings.node.nodes.size()));
+ Uninterruptibles.sleepUninterruptibly(settings.node.nodes.size(), TimeUnit.SECONDS);
+ }
+
+ maybeLoadSchemaInfo(settings);
+ }
+
+
+ private void maybeLoadSchemaInfo(StressSettings settings)
+ {
+ if (tableMetaData == null)
+ {
+ JavaDriverClient client = settings.getJavaDriverClient();
+
+ synchronized (client)
+ {
+
+ if (tableMetaData != null)
+ return;
+
+ TableMetadata metadata = client.getCluster()
+ .getMetadata()
+ .getKeyspace(keyspaceName)
+ .getTable(tableName);
+
+ //Fill in missing column configs
+ for (ColumnMetadata col : metadata.getColumns())
+ {
+ if (columnConfigs.containsKey(col.getName()))
+ continue;
+
+ columnConfigs.put(col.getName(), new GeneratorConfig(seedStr + col.getName(), null, null, null));
+ }
+
+ tableMetaData = metadata;
+ }
+ }
+ }
+
+ public SchemaQuery getQuery(String name, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ if (queryStatements == null)
+ {
+ synchronized (this)
+ {
+ if (queryStatements == null)
+ {
+ try
+ {
+ JavaDriverClient jclient = settings.getJavaDriverClient();
+ ThriftClient tclient = settings.getThriftClient();
+ Map<String, PreparedStatement> stmts = new HashMap<>();
+ Map<String, Integer> tids = new HashMap<>();
+ for (Map.Entry<String, String> e : queries.entrySet())
+ {
+ stmts.put(e.getKey().toLowerCase(), jclient.prepare(e.getValue()));
+ tids.put(e.getKey().toLowerCase(), tclient.prepare_cql3_query(e.getValue(), Compression.NONE));
+ }
+ thriftQueryIds = tids;
+ queryStatements = stmts;
+ }
+ catch (TException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+ // TODO validation
+ name = name.toLowerCase();
+ return new SchemaQuery(timer, generator, settings, thriftQueryIds.get(name), queryStatements.get(name), ThriftConversion.fromThrift(settings.command.consistencyLevel), ValidationType.NOT_FAIL);
+ }
+
+ public SchemaInsert getInsert(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ if (insertStatement == null)
+ {
+ synchronized (this)
+ {
+ if (insertStatement == null)
+ {
+ maybeLoadSchemaInfo(settings);
+
+ Set<ColumnMetadata> keyColumns = com.google.common.collect.Sets.newHashSet(tableMetaData.getPrimaryKey());
+
+ //Non PK Columns
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("UPDATE \"").append(tableName).append("\" SET ");
+
+ //PK Columns
+ StringBuilder pred = new StringBuilder();
+ pred.append(" WHERE ");
+
+ boolean firstCol = true;
+ boolean firstPred = true;
+ for (ColumnMetadata c : tableMetaData.getColumns())
+ {
+
+ if (keyColumns.contains(c))
+ {
+ if (firstPred)
+ firstPred = false;
+ else
+ pred.append(" AND ");
+
+ pred.append(c.getName()).append(" = ?");
+ }
+ else
+ {
+ if (firstCol)
+ firstCol = false;
+ else
+ sb.append(",");
+
+ sb.append(c.getName()).append(" = ");
+
+ switch (c.getType().getName())
+ {
+ case SET:
+ case LIST:
+ case COUNTER:
+ sb.append(c.getName()).append(" + ?");
+ break;
+ default:
+ sb.append("?");
+ break;
+ }
+ }
+ }
+
+ //Put PK predicates at the end
+ sb.append(pred);
+
+ if (insert == null)
+ insert = new HashMap<>();
+ lowerCase(insert);
+
+ partitions = OptionDistribution.get(!insert.containsKey("partitions") ? "fixed(1)" : insert.remove("partitions"));
+ pervisit = OptionRatioDistribution.get(!insert.containsKey("pervisit") ? "fixed(1)/1" : insert.remove("pervisit"));
+ perbatch = OptionRatioDistribution.get(!insert.containsKey("perbatch") ? "fixed(1)/1" : insert.remove("perbatch"));
+ batchType = !insert.containsKey("batchtype") ? BatchStatement.Type.UNLOGGED : BatchStatement.Type.valueOf(insert.remove("batchtype"));
+ if (!insert.isEmpty())
+ throw new IllegalArgumentException("Unrecognised insert option(s): " + insert);
+
+ if (generator.maxRowCount > 100 * 1000 * 1000)
+ System.err.printf("WARNING: You have defined a schema that permits very large partitions (%.0f max rows (>100M))\n", generator.maxRowCount);
+ if (perbatch.get().max() * pervisit.get().max() * partitions.get().maxValue() * generator.maxRowCount > 100000)
+ System.err.printf("WARNING: You have defined a schema that permits very large batches (%.0f max rows (>100K)). This may OOM this stress client, or the server.\n",
+ perbatch.get().max() * pervisit.get().max() * partitions.get().maxValue() * generator.maxRowCount);
+
+ JavaDriverClient client = settings.getJavaDriverClient();
+ String query = sb.toString();
+ try
+ {
+ thriftInsertId = settings.getThriftClient().prepare_cql3_query(query, Compression.NONE);
+ }
+ catch (TException e)
+ {
+ throw new RuntimeException(e);
+ }
+ insertStatement = client.prepare(query);
+ }
+ }
+ }
+
+ return new SchemaInsert(timer, generator, settings, partitions.get(), pervisit.get(), perbatch.get(), thriftInsertId, insertStatement, ThriftConversion.fromThrift(settings.command.consistencyLevel), batchType);
+ }
+
+ public PartitionGenerator newGenerator(StressSettings settings)
+ {
+ if (generatorFactory == null)
+ {
+ synchronized (this)
+ {
+ maybeLoadSchemaInfo(settings);
+ if (generatorFactory == null)
+ generatorFactory = new GeneratorFactory();
+ }
+ }
+
+ return generatorFactory.newGenerator();
+ }
+
+ private class GeneratorFactory
+ {
+ final List<ColumnInfo> partitionKeys = new ArrayList<>();
+ final List<ColumnInfo> clusteringColumns = new ArrayList<>();
+ final List<ColumnInfo> valueColumns = new ArrayList<>();
+
+ private GeneratorFactory()
+ {
+ Set<ColumnMetadata> keyColumns = com.google.common.collect.Sets.newHashSet(tableMetaData.getPrimaryKey());
+
+ for (ColumnMetadata metadata : tableMetaData.getPartitionKey())
+ partitionKeys.add(new ColumnInfo(metadata.getName(), metadata.getType(), columnConfigs.get(metadata.getName())));
+ for (ColumnMetadata metadata : tableMetaData.getClusteringColumns())
+ clusteringColumns.add(new ColumnInfo(metadata.getName(), metadata.getType(), columnConfigs.get(metadata.getName())));
+ for (ColumnMetadata metadata : tableMetaData.getColumns())
+ if (!keyColumns.contains(metadata))
+ valueColumns.add(new ColumnInfo(metadata.getName(), metadata.getType(), columnConfigs.get(metadata.getName())));
+ }
+
+ PartitionGenerator newGenerator()
+ {
+ return new PartitionGenerator(get(partitionKeys), get(clusteringColumns), get(valueColumns));
+ }
+
+ List<Generator> get(List<ColumnInfo> columnInfos)
+ {
+ List<Generator> result = new ArrayList<>();
+ for (ColumnInfo columnInfo : columnInfos)
+ result.add(columnInfo.getGenerator());
+ return result;
+ }
+ }
+
+ static class ColumnInfo
+ {
+ final String name;
+ final DataType type;
+ final GeneratorConfig config;
+
+ ColumnInfo(String name, DataType type, GeneratorConfig config)
+ {
+ this.name = name;
+ this.type = type;
+ this.config = config;
+ }
+
+ Generator getGenerator()
+ {
+ return getGenerator(name, type, config);
+ }
+
+ static Generator getGenerator(final String name, final DataType type, GeneratorConfig config)
+ {
+ switch (type.getName())
+ {
+ case ASCII:
+ case TEXT:
+ case VARCHAR:
+ return new Strings(name, config);
+ case BIGINT:
+ case COUNTER:
+ return new Longs(name, config);
+ case BLOB:
+ return new Bytes(name, config);
+ case BOOLEAN:
+ return new Booleans(name, config);
+ case DECIMAL:
+ case DOUBLE:
+ return new Doubles(name, config);
+ case FLOAT:
+ return new Floats(name, config);
+ case INET:
+ return new Inets(name, config);
+ case INT:
+ case VARINT:
+ return new Integers(name, config);
+ case TIMESTAMP:
+ return new Dates(name, config);
+ case UUID:
+ return new UUIDs(name, config);
+ case TIMEUUID:
+ return new TimeUUIDs(name, config);
+ case SET:
+ return new Sets(name, getGenerator(name, type.getTypeArguments().get(0), config), config);
+ case LIST:
+ return new Lists(name, getGenerator(name, type.getTypeArguments().get(0), config), config);
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+
+ public static StressProfile load(File file) throws IOError
+ {
+ try
+ {
+ byte[] profileBytes = Files.readAllBytes(Paths.get(file.toURI()));
+
+ Constructor constructor = new Constructor(StressYaml.class);
+
+ Yaml yaml = new Yaml(constructor);
+
+ StressYaml profileYaml = yaml.loadAs(new ByteArrayInputStream(profileBytes), StressYaml.class);
+
+ StressProfile profile = new StressProfile();
+ profile.init(profileYaml);
+
+ return profile;
+ }
+ catch (YAMLException | IOException | RequestValidationException e)
+ {
+ throw new IOError(e);
+ }
+ }
+
+ static <V> void lowerCase(Map<String, V> map)
+ {
+ List<Map.Entry<String, V>> reinsert = new ArrayList<>();
+ Iterator<Map.Entry<String, V>> iter = map.entrySet().iterator();
+ while (iter.hasNext())
+ {
+ Map.Entry<String, V> e = iter.next();
+ if (!e.getKey().toLowerCase().equalsIgnoreCase(e.getKey()))
+ {
+ reinsert.add(e);
+ iter.remove();
+ }
+ }
+ for (Map.Entry<String, V> e : reinsert)
+ map.put(e.getKey().toLowerCase(), e.getValue());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/StressYaml.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressYaml.java b/tools/stress/src/org/apache/cassandra/stress/StressYaml.java
new file mode 100644
index 0000000..e94fa77
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/StressYaml.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress;
+
+import java.util.List;
+import java.util.Map;
+
+public class StressYaml
+{
+ public String seed;
+ public String keyspace;
+ public String keyspace_definition;
+ public String table;
+ public String table_definition;
+
+ public List<Map<String,Object>> columnspec;
+ public Map<String,String> queries;
+ public Map<String,String> insert;
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/Distribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/Distribution.java b/tools/stress/src/org/apache/cassandra/stress/generate/Distribution.java
new file mode 100644
index 0000000..4662454
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/Distribution.java
@@ -0,0 +1,57 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.Serializable;
+
+public abstract class Distribution implements Serializable
+{
+
+ public abstract long next();
+ public abstract double nextDouble();
+ public abstract long inverseCumProb(double cumProb);
+ public abstract void setSeed(long seed);
+
+ public long maxValue()
+ {
+ return inverseCumProb(1d);
+ }
+
+ public long minValue()
+ {
+ return inverseCumProb(0d);
+ }
+
+ // approximation of the average; slightly costly to calculate, so should not be invoked frequently
+ public long average()
+ {
+ double sum = 0;
+ int count = 0;
+ for (float d = 0 ; d <= 1.0d ; d += 0.02d)
+ {
+ sum += inverseCumProb(d);
+ count += 1;
+ }
+ return (long) (sum / count);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionBoundApache.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionBoundApache.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionBoundApache.java
new file mode 100644
index 0000000..23ce3e9
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionBoundApache.java
@@ -0,0 +1,84 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.commons.math3.distribution.AbstractRealDistribution;
+
+public class DistributionBoundApache extends Distribution
+{
+
+ final AbstractRealDistribution delegate;
+ final long min, max;
+
+ public DistributionBoundApache(AbstractRealDistribution delegate, long min, long max)
+ {
+ this.delegate = delegate;
+ this.min = min;
+ this.max = max;
+ }
+
+ @Override
+ public long next()
+ {
+ return bound(min, max, delegate.sample());
+ }
+
+ public double nextDouble()
+ {
+ return boundDouble(min, max, delegate.sample());
+ }
+
+ @Override
+ public long inverseCumProb(double cumProb)
+ {
+ return bound(min, max, delegate.inverseCumulativeProbability(cumProb));
+ }
+
+ public void setSeed(long seed)
+ {
+ delegate.reseedRandomGenerator(seed);
+ }
+
+ private static long bound(long min, long max, double val)
+ {
+ long r = (long) val;
+ if ((r >= min) & (r <= max))
+ return r;
+ if (r < min)
+ return min;
+ if (r > max)
+ return max;
+ throw new IllegalStateException();
+ }
+
+ private static double boundDouble(long min, long max, double r)
+ {
+ if ((r >= min) & (r <= max))
+ return r;
+ if (r < min)
+ return min;
+ if (r > max)
+ return max;
+ throw new IllegalStateException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFactory.java
new file mode 100644
index 0000000..d0dfa89
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFactory.java
@@ -0,0 +1,31 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.Serializable;
+
+public interface DistributionFactory extends Serializable
+{
+
+ Distribution get();
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFixed.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFixed.java
new file mode 100644
index 0000000..bbfb894
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFixed.java
@@ -0,0 +1,54 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+public class DistributionFixed extends Distribution
+{
+
+ final long key;
+
+ public DistributionFixed(long key)
+ {
+ this.key = key;
+ }
+
+ @Override
+ public long next()
+ {
+ return key;
+ }
+
+ public double nextDouble()
+ {
+ return key;
+ }
+
+ @Override
+ public long inverseCumProb(double cumProb)
+ {
+ return key;
+ }
+
+ public void setSeed(long seed)
+ {
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionInverted.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionInverted.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionInverted.java
new file mode 100644
index 0000000..df52cb8
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionInverted.java
@@ -0,0 +1,37 @@
+package org.apache.cassandra.stress.generate;
+
+public class DistributionInverted extends Distribution
+{
+
+ final Distribution wrapped;
+ final long min;
+ final long max;
+
+ public DistributionInverted(Distribution wrapped)
+ {
+ this.wrapped = wrapped;
+ this.min = wrapped.minValue();
+ this.max = wrapped.maxValue();
+ }
+
+ public long next()
+ {
+ return max - (wrapped.next() - min);
+ }
+
+ public double nextDouble()
+ {
+ return max - (wrapped.nextDouble() - min);
+ }
+
+ public long inverseCumProb(double cumProb)
+ {
+ return max - (wrapped.inverseCumProb(cumProb) - min);
+ }
+
+ public void setSeed(long seed)
+ {
+ wrapped.setSeed(seed);
+ }
+
+}
[12/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionOffsetApache.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionOffsetApache.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionOffsetApache.java
deleted file mode 100644
index cfbc385..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionOffsetApache.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import org.apache.commons.math3.distribution.AbstractRealDistribution;
-
-public class DistributionOffsetApache extends Distribution
-{
-
- final AbstractRealDistribution delegate;
- final long min, delta;
-
- public DistributionOffsetApache(AbstractRealDistribution delegate, long min, long max)
- {
- this.delegate = delegate;
- this.min = min;
- this.delta = max - min;
- }
-
- @Override
- public long next()
- {
- return offset(min, delta, delegate.sample());
- }
-
- @Override
- public long inverseCumProb(double cumProb)
- {
- return offset(min, delta, delegate.inverseCumulativeProbability(cumProb));
- }
-
- private long offset(long min, long delta, double val)
- {
- long r = (long) val;
- if (r < 0)
- r = 0;
- if (r > delta)
- r = delta;
- return min + r;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionSeqBatch.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionSeqBatch.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionSeqBatch.java
deleted file mode 100644
index 8e1a5d5..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionSeqBatch.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-public class DistributionSeqBatch extends DataGenHex
-{
-
- final Distribution delegate;
- final int batchSize;
- final long maxKey;
-
- private int batchIndex;
- private long batchKey;
-
- // object must be published safely if passed between threadCount, due to batchIndex not being volatile. various
- // hacks possible, but not ideal. don't want to use volatile as object intended for single threaded use.
- public DistributionSeqBatch(int batchSize, long maxKey, Distribution delegate)
- {
- this.batchIndex = batchSize;
- this.batchSize = batchSize;
- this.maxKey = maxKey;
- this.delegate = delegate;
- }
-
- @Override
- long next(long operationIndex)
- {
- if (batchIndex >= batchSize)
- {
- batchKey = delegate.next();
- batchIndex = 0;
- }
- long r = batchKey + batchIndex++;
- if (r > maxKey)
- {
- batchKey = delegate.next();
- batchIndex = 1;
- r = batchKey;
- }
- return r;
- }
-
- @Override
- public boolean isDeterministic()
- {
- return false;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/KeyGen.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/KeyGen.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/KeyGen.java
deleted file mode 100644
index dad5918..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/KeyGen.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-
-public class KeyGen
-{
-
- final DataGen dataGen;
- final int keySize;
- final List<ByteBuffer> keyBuffers = new ArrayList<>();
-
- public KeyGen(DataGen dataGen, int keySize)
- {
- this.dataGen = dataGen;
- this.keySize = keySize;
- }
-
- public List<ByteBuffer> getKeys(int n, long index)
- {
- while (keyBuffers.size() < n)
- keyBuffers.add(ByteBuffer.wrap(new byte[keySize]));
- dataGen.generate(keyBuffers, index, null);
- return keyBuffers;
- }
-
- public boolean isDeterministic()
- {
- return dataGen.isDeterministic();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java
deleted file mode 100644
index 9c6ca43..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.List;
-
-/**
- * Generates a row of data, by constructing one byte buffers per column according to some algorithm
- * and delegating the work of populating the values of those byte buffers to the provided data generator
- */
-public abstract class RowGen
-{
-
- final DataGen dataGen;
- protected RowGen(DataGen dataGenerator)
- {
- this.dataGen = dataGenerator;
- }
-
- public List<ByteBuffer> generate(long operationIndex, ByteBuffer key)
- {
- List<ByteBuffer> fill = getColumns(operationIndex);
- dataGen.generate(fill, operationIndex, key);
- return fill;
- }
-
- // these byte[] may be re-used
- abstract List<ByteBuffer> getColumns(long operationIndex);
- abstract public int count(long operationIndex);
-
- abstract public boolean isDeterministic();
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java
deleted file mode 100644
index fffad2f..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-public class RowGenDistributedSize extends RowGen
-{
-
- // TODO - make configurable
- static final int MAX_SINGLE_CACHE_SIZE = 16 * 1024;
-
- final Distribution countDistribution;
- final Distribution sizeDistribution;
-
- final TreeMap<Integer, ByteBuffer> cache = new TreeMap<>();
-
- // array re-used for returning columns
- final ByteBuffer[] ret;
- final int[] sizes;
-
- final boolean isDeterministic;
-
- public RowGenDistributedSize(DataGen dataGenerator, Distribution countDistribution, Distribution sizeDistribution)
- {
- super(dataGenerator);
- this.countDistribution = countDistribution;
- 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();
- }
-
- ByteBuffer getBuffer(int size)
- {
- if (size >= MAX_SINGLE_CACHE_SIZE)
- return ByteBuffer.allocate(size);
- Map.Entry<Integer, ByteBuffer> found = cache.ceilingEntry(size);
- if (found == null)
- {
- // remove the next entry down, and replace it with a cache of this size
- Integer del = cache.lowerKey(size);
- if (del != null)
- cache.remove(del);
- return ByteBuffer.allocate(size);
- }
- ByteBuffer r = found.getValue();
- cache.remove(found.getKey());
- return r;
- }
-
- @Override
- List<ByteBuffer> getColumns(long operationIndex)
- {
- int i = 0;
- int count = (int) countDistribution.next();
- while (i < count)
- {
- int columnSize = (int) sizeDistribution.next();
- sizes[i] = columnSize;
- ret[i] = getBuffer(columnSize);
- i++;
- }
- while (i < ret.length && ret[i] != null)
- ret[i] = null;
- i = 0;
- while (i < count)
- {
- ByteBuffer b = ret[i];
- cache.put(b.capacity(), b);
- b.position(b.capacity() - sizes[i]);
- ret[i] = b.slice();
- b.position(0);
- i++;
- }
- return Arrays.asList(ret).subList(0, count);
- }
-
- public int count(long operationIndex)
- {
- return (int) countDistribution.next();
- }
-
- @Override
- public boolean isDeterministic()
- {
- return isDeterministic;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java
deleted file mode 100644
index 9a8c37d..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-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<Integer>
-{
- public CqlCounterAdder(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected String buildQuery()
- {
- String counterCF = state.isCql2() ? state.type.table : "Counter3";
-
- StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(counterCF));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- query.append(" SET ");
-
- // TODO : increment distribution subset of columns
- for (int i = 0; i < state.settings.columns.maxColumnsPerKey; i++)
- {
- if (i > 0)
- query.append(",");
-
- query.append('C').append(i).append("=C").append(i).append("+?");
- }
- query.append(" WHERE KEY=?");
- return query.toString();
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- final List<Object> 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<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new CqlRunOpAlwaysSucceed(client, query, queryId, params, keyid, key, 1);
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java
deleted file mode 100644
index 88d622e..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.List;
-
-public class CqlCounterGetter extends CqlOperation<Integer>
-{
-
- public CqlCounterGetter(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- return Collections.<Object>singletonList(ByteBuffer.wrap(key));
- }
-
- @Override
- protected String buildQuery()
- {
- 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() ? state.type.table : "Counter3";
-
- query.append(" FROM ").append(wrapInQuotesIfRequired(counterCF));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- return query.append(" WHERE KEY=?").toString();
- }
-
- @Override
- protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new CqlRunOpTestNonEmpty(client, query, queryId, params, keyid, key);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java
deleted file mode 100644
index 046381e..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
-*
-* 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.
-*
-*/
-
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.cassandra.utils.FBUtilities;
-
-public class CqlIndexedRangeSlicer extends CqlOperation<byte[][]>
-{
-
- volatile boolean acceptNoResults = false;
-
- public CqlIndexedRangeSlicer(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected String buildQuery()
- {
- StringBuilder query = new StringBuilder("SELECT");
- query.append(wrapInQuotesIfRequired("key"));
- query.append(" FROM ");
- query.append(wrapInQuotesIfRequired(state.type.table));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- final String columnName = (state.settings.columns.namestrs.get(1));
- query.append(" WHERE ").append(columnName).append("=?")
- .append(" AND KEY > ? LIMIT ").append(state.settings.command.keysAtOnce);
- return query.toString();
- }
-
- @Override
- protected void run(CqlOperation.ClientWrapper client) throws IOException
- {
- acceptNoResults = false;
- final List<ByteBuffer> columns = generateColumnValues(getKey());
- final ByteBuffer value = columns.get(1); // only C1 column is indexed
- byte[] minKey = new byte[0];
- int rowCount;
- do
- {
- List<Object> params = Arrays.<Object>asList(value, ByteBuffer.wrap(minKey));
- CqlRunOp<byte[][]> op = run(client, params, value, new String(value.array()));
- byte[][] keys = op.result;
- rowCount = keys.length;
- minKey = getNextMinKey(minKey, keys);
- acceptNoResults = true;
- } while (rowCount > 0);
- }
-
- private final class IndexedRangeSliceRunOp extends CqlRunOpFetchKeys
- {
-
- protected IndexedRangeSliceRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- super(client, query, queryId, params, keyid, key);
- }
-
- @Override
- public boolean validate(byte[][] result)
- {
- return acceptNoResults || result.length > 0;
- }
- }
-
- @Override
- protected CqlRunOp<byte[][]> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new IndexedRangeSliceRunOp(client, query, queryId, params, keyid, key);
- }
-
- private static byte[] getNextMinKey(byte[] cur, byte[][] keys)
- {
- // find max
- for (byte[] key : keys)
- if (FBUtilities.compareUnsigned(cur, key) < 0)
- cur = key;
-
- // increment
- for (int i = 0 ; i < cur.length ; i++)
- if (++cur[i] != 0)
- break;
- return cur;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java
deleted file mode 100644
index 71cdadf..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.cassandra.utils.UUIDGen;
-
-public class CqlInserter extends CqlOperation<Integer>
-{
-
- 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.type.table));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- query.append(" SET ");
-
- for (int i = 0 ; i < state.settings.columns.maxColumnsPerKey; i++)
- {
- if (i > 0)
- query.append(',');
-
- if (state.settings.columns.useTimeUUIDComparator)
- {
- if (state.isCql3())
- throw new UnsupportedOperationException("Cannot use UUIDs in column names with CQL3");
-
- query.append(wrapInQuotesIfRequired(UUIDGen.getTimeUUID().toString()))
- .append(" = ?");
- }
- else
- {
- query.append(wrapInQuotesIfRequired("C" + i)).append(" = ?");
- }
- }
-
- query.append(" WHERE KEY=?");
- return query.toString();
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- final ArrayList<Object> queryParams = new ArrayList<>();
- final List<ByteBuffer> values = generateColumnValues(ByteBuffer.wrap(key));
- queryParams.addAll(values);
- queryParams.add(ByteBuffer.wrap(key));
- return queryParams;
- }
-
- @Override
- protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new CqlRunOpAlwaysSucceed(client, query, queryId, params, keyid, key, 1);
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlMultiGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlMultiGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlMultiGetter.java
deleted file mode 100644
index 80a7118..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlMultiGetter.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.IOException;
-
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.util.ThriftClient;
-
-public class CqlMultiGetter extends Operation
-{
- public CqlMultiGetter(State state, long idx)
- {
- super(state, idx);
- throw new RuntimeException("Multiget is not implemented for CQL");
- }
-
- @Override
- public void run(ThriftClient client) throws IOException
- {
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java
deleted file mode 100644
index 1c59e2d..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import com.datastax.driver.core.PreparedStatement;
-import com.datastax.driver.core.ResultSet;
-import com.datastax.driver.core.Row;
-import com.google.common.base.Function;
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.settings.ConnectionStyle;
-import org.apache.cassandra.stress.settings.CqlVersion;
-import org.apache.cassandra.stress.util.JavaDriverClient;
-import org.apache.cassandra.stress.util.ThriftClient;
-import org.apache.cassandra.thrift.Compression;
-import org.apache.cassandra.thrift.CqlResult;
-import org.apache.cassandra.thrift.CqlRow;
-import org.apache.cassandra.thrift.ThriftConversion;
-import org.apache.cassandra.transport.SimpleClient;
-import org.apache.cassandra.transport.messages.ResultMessage;
-import org.apache.cassandra.utils.ByteBufferUtil;
-import org.apache.thrift.TException;
-
-public abstract class CqlOperation<V> extends Operation
-{
-
- protected abstract List<Object> getQueryParameters(byte[] key);
- protected abstract String buildQuery();
- protected abstract CqlRunOp<V> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String id, ByteBuffer key);
-
- public CqlOperation(State state, long idx)
- {
- super(state, idx);
- if (state.settings.columns.useSuperColumns)
- 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<V> run(final ClientWrapper client, final List<Object> queryParams, final ByteBuffer key, final String keyid) throws IOException
- {
- final CqlRunOp<V> op;
- if (state.settings.mode.style == ConnectionStyle.CQL_PREPARED)
- {
- final Object id;
- Object idobj = state.getCqlCache();
- if (idobj == null)
- {
- try
- {
- id = client.createPreparedStatement(buildQuery());
- } catch (TException e)
- {
- throw new RuntimeException(e);
- }
- state.storeCqlCache(id);
- }
- else
- id = idobj;
-
- op = buildRunOp(client, null, id, queryParams, keyid, key);
- }
- else
- {
- final String query;
- Object qobj = state.getCqlCache();
- if (qobj == null)
- state.storeCqlCache(query = buildQuery());
- else
- query = qobj.toString();
-
- op = buildRunOp(client, query, null, queryParams, keyid, key);
- }
-
- timeWithRetry(op);
- return op;
- }
-
- protected void run(final ClientWrapper client) throws IOException
- {
- final byte[] key = getKey().array();
- final List<Object> queryParams = getQueryParameters(key);
- run(client, queryParams, ByteBuffer.wrap(key), new String(key));
- }
-
- // Classes to process Cql results
-
- // Always succeeds so long as the query executes without error; provides a keyCount to increment on instantiation
- protected final class CqlRunOpAlwaysSucceed extends CqlRunOp<Integer>
- {
-
- final int keyCount;
-
- protected CqlRunOpAlwaysSucceed(ClientWrapper client, String query, Object queryId, List<Object> params, String id, ByteBuffer key, int keyCount)
- {
- super(client, query, queryId, RowCountHandler.INSTANCE, params, id, key);
- this.keyCount = keyCount;
- }
-
- @Override
- public boolean validate(Integer result)
- {
- return true;
- }
-
- @Override
- public int keyCount()
- {
- return keyCount;
- }
- }
-
- // Succeeds so long as the result set is nonempty, and the query executes without error
- protected final class CqlRunOpTestNonEmpty extends CqlRunOp<Integer>
- {
-
- protected CqlRunOpTestNonEmpty(ClientWrapper client, String query, Object queryId, List<Object> params, String id, ByteBuffer key)
- {
- super(client, query, queryId, RowCountHandler.INSTANCE, params, id, key);
- }
-
- @Override
- public boolean validate(Integer result)
- {
- return result > 0;
- }
-
- @Override
- public int keyCount()
- {
- return result;
- }
- }
-
- // Requires a custom validate() method, but fetches and stores the keys from the result set for further processing
- protected abstract class CqlRunOpFetchKeys extends CqlRunOp<byte[][]>
- {
-
- protected CqlRunOpFetchKeys(ClientWrapper client, String query, Object queryId, List<Object> params, String id, ByteBuffer key)
- {
- super(client, query, queryId, KeysHandler.INSTANCE, params, id, key);
- }
-
- @Override
- public int keyCount()
- {
- return result.length;
- }
-
- }
-
- protected final class CqlRunOpMatchResults extends CqlRunOp<ByteBuffer[][]>
- {
-
- final List<List<ByteBuffer>> 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<Object> params, String id, ByteBuffer key, List<List<ByteBuffer>> expect)
- {
- super(client, query, queryId, RowsHandler.INSTANCE, params, id, key);
- this.expect = expect;
- }
-
- @Override
- public int keyCount()
- {
- return result == null ? 0 : result.length;
- }
-
- public boolean validate(ByteBuffer[][] result)
- {
- if (result.length != expect.size())
- return false;
- for (int i = 0 ; i < result.length ; i++)
- if (expect.get(i) != null && !expect.get(i).equals(Arrays.asList(result[i])))
- return false;
- return true;
- }
- }
-
- // Cql
- protected abstract class CqlRunOp<V> implements RunOp
- {
-
- final ClientWrapper client;
- final String query;
- final Object queryId;
- final List<Object> params;
- final String id;
- final ByteBuffer key;
- final ResultHandler<V> handler;
- V result;
-
- private CqlRunOp(ClientWrapper client, String query, Object queryId, ResultHandler<V> handler, List<Object> params, String id, ByteBuffer key)
- {
- this.client = client;
- this.query = query;
- this.queryId = queryId;
- this.handler = handler;
- this.params = params;
- this.id = id;
- this.key = key;
- }
-
- @Override
- public boolean run() throws Exception
- {
- return queryId != null
- ? validate(result = client.execute(queryId, key, params, handler))
- : validate(result = client.execute(query, key, params, handler));
- }
-
- @Override
- public String key()
- {
- return id;
- }
-
- public abstract boolean validate(V result);
-
- }
-
-
- /// LOTS OF WRAPPING/UNWRAPPING NONSENSE
-
-
- @Override
- public void run(final ThriftClient client) throws IOException
- {
- run(wrap(client));
- }
-
- @Override
- public void run(SimpleClient client) throws IOException
- {
- run(wrap(client));
- }
-
- @Override
- public void run(JavaDriverClient client) throws IOException
- {
- run(wrap(client));
- }
-
- public ClientWrapper wrap(ThriftClient client)
- {
- return state.isCql3()
- ? new Cql3CassandraClientWrapper(client)
- : new Cql2CassandraClientWrapper(client);
-
- }
-
- public ClientWrapper wrap(JavaDriverClient client)
- {
- return new JavaDriverWrapper(client);
- }
-
- public ClientWrapper wrap(SimpleClient client)
- {
- return new SimpleClientWrapper(client);
- }
-
- protected interface ClientWrapper
- {
- Object createPreparedStatement(String cqlQuery) throws TException;
- <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
- <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
- }
-
- private final class JavaDriverWrapper implements ClientWrapper
- {
- final JavaDriverClient client;
- private JavaDriverWrapper(JavaDriverClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
- {
- String formattedQuery = formatCqlQuery(query, queryParams, state.isCql3());
- return handler.javaDriverHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(state.settings.command.consistencyLevel)));
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
- {
- return handler.javaDriverHandler().apply(
- client.executePrepared(
- (PreparedStatement) preparedStatementId,
- queryParams,
- ThriftConversion.fromThrift(state.settings.command.consistencyLevel)));
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery)
- {
- return client.prepare(cqlQuery);
- }
- }
-
- private final class SimpleClientWrapper implements ClientWrapper
- {
- final SimpleClient client;
- private SimpleClientWrapper(SimpleClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
- {
- String formattedQuery = formatCqlQuery(query, queryParams, state.isCql3());
- return handler.thriftHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(state.settings.command.consistencyLevel)));
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
- {
- return handler.thriftHandler().apply(
- client.executePrepared(
- (byte[]) preparedStatementId,
- toByteBufferParams(queryParams),
- ThriftConversion.fromThrift(state.settings.command.consistencyLevel)));
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery)
- {
- return client.prepare(cqlQuery).statementId.bytes;
- }
- }
-
- // client wrapper for Cql3
- private final class Cql3CassandraClientWrapper implements ClientWrapper
- {
- final ThriftClient client;
- private Cql3CassandraClientWrapper(ThriftClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- String formattedQuery = formatCqlQuery(query, queryParams, true);
- return handler.simpleNativeHandler().apply(
- client.execute_cql3_query(formattedQuery, key, Compression.NONE, state.settings.command.consistencyLevel)
- );
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- Integer id = (Integer) preparedStatementId;
- return handler.simpleNativeHandler().apply(
- client.execute_prepared_cql3_query(id, key, toByteBufferParams(queryParams), state.settings.command.consistencyLevel)
- );
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery) throws TException
- {
- return client.prepare_cql3_query(cqlQuery, Compression.NONE);
- }
- }
-
- // client wrapper for Cql2
- private final class Cql2CassandraClientWrapper implements ClientWrapper
- {
- final ThriftClient client;
- private Cql2CassandraClientWrapper(ThriftClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- String formattedQuery = formatCqlQuery(query, queryParams, false);
- return handler.simpleNativeHandler().apply(
- client.execute_cql_query(formattedQuery, key, Compression.NONE)
- );
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- Integer id = (Integer) preparedStatementId;
- return handler.simpleNativeHandler().apply(
- client.execute_prepared_cql_query(id, key, toByteBufferParams(queryParams))
- );
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery) throws TException
- {
- return client.prepare_cql_query(cqlQuery, Compression.NONE);
- }
- }
-
- // interface for building functions to standardise results from each client
- protected static interface ResultHandler<V>
- {
- Function<ResultSet, V> javaDriverHandler();
- Function<ResultMessage, V> thriftHandler();
- Function<CqlResult, V> simpleNativeHandler();
- }
-
- protected static class RowCountHandler implements ResultHandler<Integer>
- {
- static final RowCountHandler INSTANCE = new RowCountHandler();
-
- @Override
- public Function<ResultSet, Integer> javaDriverHandler()
- {
- return new Function<ResultSet, Integer>()
- {
- @Override
- public Integer apply(ResultSet rows)
- {
- if (rows == null)
- return 0;
- return rows.all().size();
- }
- };
- }
-
- @Override
- public Function<ResultMessage, Integer> thriftHandler()
- {
- return new Function<ResultMessage, Integer>()
- {
- @Override
- public Integer apply(ResultMessage result)
- {
- return result instanceof ResultMessage.Rows ? ((ResultMessage.Rows) result).result.size() : 0;
- }
- };
- }
-
- @Override
- public Function<CqlResult, Integer> simpleNativeHandler()
- {
- return new Function<CqlResult, Integer>()
- {
-
- @Override
- public Integer apply(CqlResult result)
- {
- switch (result.getType())
- {
- case ROWS:
- return result.getRows().size();
- default:
- return 1;
- }
- }
- };
- }
-
- }
-
- // Processes results from each client into an array of all key bytes returned
- protected static final class RowsHandler implements ResultHandler<ByteBuffer[][]>
- {
- static final RowsHandler INSTANCE = new RowsHandler();
-
- @Override
- public Function<ResultSet, ByteBuffer[][]> javaDriverHandler()
- {
- return new Function<ResultSet, ByteBuffer[][]>()
- {
-
- @Override
- public ByteBuffer[][] apply(ResultSet result)
- {
- if (result == null)
- return new ByteBuffer[0][];
- List<Row> rows = result.all();
-
- ByteBuffer[][] r = new ByteBuffer[rows.size()][];
- for (int i = 0 ; i < r.length ; i++)
- {
- Row row = rows.get(i);
- r[i] = new ByteBuffer[row.getColumnDefinitions().size()];
- for (int j = 0 ; j < row.getColumnDefinitions().size() ; j++)
- r[i][j] = row.getBytes(j);
- }
- return r;
- }
- };
- }
-
- @Override
- public Function<ResultMessage, ByteBuffer[][]> thriftHandler()
- {
- return new Function<ResultMessage, ByteBuffer[][]>()
- {
-
- @Override
- public ByteBuffer[][] apply(ResultMessage result)
- {
- if (!(result instanceof ResultMessage.Rows))
- return new ByteBuffer[0][];
-
- ResultMessage.Rows rows = ((ResultMessage.Rows) result);
- ByteBuffer[][] r = new ByteBuffer[rows.result.size()][];
- for (int i = 0 ; i < r.length ; i++)
- {
- List<ByteBuffer> row = rows.result.rows.get(i);
- r[i] = new ByteBuffer[row.size()];
- for (int j = 0 ; j < row.size() ; j++)
- r[i][j] = row.get(j);
- }
- return r;
- }
- };
- }
-
- @Override
- public Function<CqlResult, ByteBuffer[][]> simpleNativeHandler()
- {
- return new Function<CqlResult, ByteBuffer[][]>()
- {
-
- @Override
- public ByteBuffer[][] apply(CqlResult result)
- {
- ByteBuffer[][] r = new ByteBuffer[result.getRows().size()][];
- for (int i = 0 ; i < r.length ; i++)
- {
- CqlRow row = result.getRows().get(i);
- r[i] = new ByteBuffer[row.getColumns().size()];
- for (int j = 0 ; j < r[i].length ; j++)
- r[i][j] = ByteBuffer.wrap(row.getColumns().get(j).getValue());
- }
- return r;
- }
- };
- }
-
- }
- // Processes results from each client into an array of all key bytes returned
- protected static final class KeysHandler implements ResultHandler<byte[][]>
- {
- static final KeysHandler INSTANCE = new KeysHandler();
-
- @Override
- public Function<ResultSet, byte[][]> javaDriverHandler()
- {
- return new Function<ResultSet, byte[][]>()
- {
-
- @Override
- public byte[][] apply(ResultSet result)
- {
-
- if (result == null)
- return new byte[0][];
- List<Row> rows = result.all();
- byte[][] r = new byte[rows.size()][];
- for (int i = 0 ; i < r.length ; i++)
- r[i] = rows.get(i).getBytes(0).array();
- return r;
- }
- };
- }
-
- @Override
- public Function<ResultMessage, byte[][]> thriftHandler()
- {
- return new Function<ResultMessage, byte[][]>()
- {
-
- @Override
- public byte[][] apply(ResultMessage result)
- {
- if (result instanceof ResultMessage.Rows)
- {
- ResultMessage.Rows rows = ((ResultMessage.Rows) result);
- byte[][] r = new byte[rows.result.size()][];
- for (int i = 0 ; i < r.length ; i++)
- r[i] = rows.result.rows.get(i).get(0).array();
- return r;
- }
- return null;
- }
- };
- }
-
- @Override
- public Function<CqlResult, byte[][]> simpleNativeHandler()
- {
- return new Function<CqlResult, byte[][]>()
- {
-
- @Override
- public byte[][] apply(CqlResult result)
- {
- byte[][] r = new byte[result.getRows().size()][];
- for (int i = 0 ; i < r.length ; i++)
- r[i] = result.getRows().get(i).getKey();
- return r;
- }
- };
- }
-
- }
-
- private static String getUnQuotedCqlBlob(ByteBuffer term, boolean isCQL3)
- {
- return isCQL3
- ? "0x" + ByteBufferUtil.bytesToHex(term)
- : ByteBufferUtil.bytesToHex(term);
- }
-
- /**
- * Constructs a CQL query string by replacing instances of the character
- * '?', with the corresponding parameter.
- *
- * @param query base query string to format
- * @param parms sequence of string query parameters
- * @return formatted CQL query string
- */
- private static String formatCqlQuery(String query, List<Object> parms, boolean isCql3)
- {
- int marker, position = 0;
- StringBuilder result = new StringBuilder();
-
- if (-1 == (marker = query.indexOf('?')) || parms.size() == 0)
- return query;
-
- for (Object parm : parms)
- {
- result.append(query.substring(position, marker));
- 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)))
- break;
- }
-
- if (position < query.length())
- result.append(query.substring(position));
-
- return result.toString();
- }
-
- private static List<ByteBuffer> toByteBufferParams(List<Object> params)
- {
- List<ByteBuffer> 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
- ? "\"" + string + "\""
- : string;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java
deleted file mode 100644
index 16cdff3..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.List;
-
-public class CqlRangeSlicer extends CqlOperation<Integer>
-{
- public CqlRangeSlicer(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- return Collections.<Object>singletonList(ByteBuffer.wrap(key));
- }
-
- @Override
- protected String buildQuery()
- {
- StringBuilder query = new StringBuilder("SELECT FIRST ").append(state.settings.columns.maxColumnsPerKey)
- .append(" ''..'' FROM ").append(wrapInQuotesIfRequired(state.type.table));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- return query.append(" WHERE KEY > ?").toString();
- }
-
- @Override
- protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new CqlRunOpTestNonEmpty(client, query, queryId, params, keyid, key);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java
deleted file mode 100644
index fb07edc..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.cassandra.utils.ByteBufferUtil;
-
-public class CqlReader extends CqlOperation<ByteBuffer[][]>
-{
-
- public CqlReader(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected String buildQuery()
- {
- StringBuilder query = new StringBuilder("SELECT ");
-
- if (state.settings.columns.slice)
- {
- if (state.isCql2())
- query.append("FIRST ").append(state.settings.columns.maxColumnsPerKey).append(" ''..''");
- else
- query.append("*");
- }
- else
- {
- try
- {
- for (int i = 0; i < state.settings.columns.names.size() ; i++)
- {
- if (i > 0)
- query.append(",");
- query.append(wrapInQuotesIfRequired(ByteBufferUtil.string(state.settings.columns.names.get(i))));
- }
- }
- catch (CharacterCodingException e)
- {
- throw new IllegalStateException(e);
- }
- }
-
- query.append(" FROM ").append(wrapInQuotesIfRequired(state.type.table));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
- query.append(" WHERE KEY=?");
- return query.toString();
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- return Collections.<Object>singletonList(ByteBuffer.wrap(key));
- }
-
- @Override
- protected CqlRunOp<ByteBuffer[][]> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- List<ByteBuffer> expectRow = state.rowGen.isDeterministic() ? generateColumnValues(key) : null;
- return new CqlRunOpMatchResults(client, query, queryId, params, keyid, key, Arrays.asList(expectRow));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java b/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
new file mode 100644
index 0000000..914d212
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
@@ -0,0 +1,25 @@
+package org.apache.cassandra.stress.operations;
+
+import org.apache.cassandra.stress.Operation;
+
+public class FixedOpDistribution implements OpDistribution
+{
+
+ final Operation operation;
+
+ public FixedOpDistribution(Operation operation)
+ {
+ this.operation = operation;
+ }
+
+ public Operation next()
+ {
+ return operation;
+ }
+
+ public int maxBatchSize()
+ {
+ return (int) operation.partitionCount.maxValue();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
new file mode 100644
index 0000000..a744f18
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
@@ -0,0 +1,11 @@
+package org.apache.cassandra.stress.operations;
+
+import org.apache.cassandra.stress.Operation;
+
+public interface OpDistribution
+{
+
+ Operation next();
+ public int maxBatchSize();
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
new file mode 100644
index 0000000..08d5f56
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
@@ -0,0 +1,12 @@
+package org.apache.cassandra.stress.operations;
+
+import org.apache.cassandra.stress.util.Timer;
+
+public interface OpDistributionFactory
+{
+
+ public OpDistribution get(Timer timer);
+ public String desc();
+ Iterable<OpDistributionFactory> each();
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
new file mode 100644
index 0000000..8bd2806
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
@@ -0,0 +1,41 @@
+package org.apache.cassandra.stress.operations;
+
+import org.apache.commons.math3.distribution.EnumeratedDistribution;
+import org.apache.commons.math3.util.Pair;
+
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.generate.Distribution;
+
+public class SampledOpDistribution implements OpDistribution
+{
+
+ final EnumeratedDistribution<Operation> operations;
+ final Distribution clustering;
+ private Operation cur;
+ private long remaining;
+
+ public SampledOpDistribution(EnumeratedDistribution<Operation> operations, Distribution clustering)
+ {
+ this.operations = operations;
+ this.clustering = clustering;
+ }
+
+ public int maxBatchSize()
+ {
+ int max = 1;
+ for (Pair<Operation, Double> pair : operations.getPmf())
+ max = Math.max(max, (int) pair.getFirst().partitionCount.maxValue());
+ return max;
+ }
+
+ public Operation next()
+ {
+ while (remaining == 0)
+ {
+ remaining = clustering.next();
+ cur = operations.sample();
+ }
+ remaining--;
+ return cur;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
new file mode 100644
index 0000000..575da12
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
@@ -0,0 +1,72 @@
+package org.apache.cassandra.stress.operations;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.math3.distribution.EnumeratedDistribution;
+import org.apache.commons.math3.util.Pair;
+
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.util.Timer;
+
+public abstract class SampledOpDistributionFactory<T> implements OpDistributionFactory
+{
+
+ final List<Pair<T, Double>> ratios;
+ final DistributionFactory clustering;
+ protected SampledOpDistributionFactory(List<Pair<T, Double>> ratios, DistributionFactory clustering)
+ {
+ this.ratios = ratios;
+ this.clustering = clustering;
+ }
+
+ protected abstract Operation get(Timer timer, PartitionGenerator generator, T key);
+ protected abstract PartitionGenerator newGenerator();
+
+ public OpDistribution get(Timer timer)
+ {
+ PartitionGenerator generator = newGenerator();
+ List<Pair<Operation, Double>> operations = new ArrayList<>();
+ for (Pair<T, Double> ratio : ratios)
+ operations.add(new Pair<>(get(timer, generator, ratio.getFirst()), ratio.getSecond()));
+ return new SampledOpDistribution(new EnumeratedDistribution<>(operations), clustering.get());
+ }
+
+ public String desc()
+ {
+ List<T> keys = new ArrayList<>();
+ for (Pair<T, Double> p : ratios)
+ keys.add(p.getFirst());
+ return keys.toString();
+ }
+
+ public Iterable<OpDistributionFactory> each()
+ {
+ List<OpDistributionFactory> out = new ArrayList<>();
+ for (final Pair<T, Double> ratio : ratios)
+ {
+ out.add(new OpDistributionFactory()
+ {
+ public OpDistribution get(Timer timer)
+ {
+ return new FixedOpDistribution(SampledOpDistributionFactory.this.get(timer, newGenerator(), ratio.getFirst()));
+ }
+
+ public String desc()
+ {
+ return ratio.getFirst().toString();
+ }
+
+ public Iterable<OpDistributionFactory> each()
+ {
+ return Collections.<OpDistributionFactory>singleton(this);
+ }
+ });
+ }
+ return out;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java
deleted file mode 100644
index 9bfe440..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-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;
-import org.apache.cassandra.thrift.*;
-
-public class ThriftCounterAdder extends Operation
-{
- public ThriftCounterAdder(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
- List<CounterColumn> columns = new ArrayList<>();
- for (ByteBuffer name : randomNames())
- columns.add(new CounterColumn(name, state.counteradd.next()));
-
- Map<String, List<Mutation>> row;
- if (state.settings.columns.useSuperColumns)
- {
- List<Mutation> mutations = new ArrayList<>();
- for (ColumnParent parent : state.columnParents)
- {
- CounterSuperColumn csc = new CounterSuperColumn(ByteBuffer.wrap(parent.getSuper_column()), columns);
- ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setCounter_super_column(csc);
- mutations.add(new Mutation().setColumn_or_supercolumn(cosc));
- }
- row = Collections.singletonMap(state.type.supertable, mutations);
- }
- else
- {
- List<Mutation> mutations = new ArrayList<>(columns.size());
- for (CounterColumn c : columns)
- {
- ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setCounter_column(c);
- mutations.add(new Mutation().setColumn_or_supercolumn(cosc));
- }
- row = Collections.singletonMap(state.type.table, mutations);
- }
-
- final ByteBuffer key = getKey();
- final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
-
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- client.batch_mutate(record, state.settings.command.consistencyLevel);
- return true;
- }
-
- @Override
- public String key()
- {
- return new String(key.array());
- }
-
- @Override
- public int keyCount()
- {
- return 1;
- }
- });
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java
deleted file mode 100644
index 6e36a28..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.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;
-import org.apache.cassandra.thrift.ColumnParent;
-import org.apache.cassandra.thrift.SlicePredicate;
-import org.apache.cassandra.thrift.SliceRange;
-
-public class ThriftCounterGetter extends Operation
-{
- public ThriftCounterGetter(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
- final SlicePredicate predicate = slicePredicate();
- final ByteBuffer key = getKey();
- for (final ColumnParent parent : state.columnParents)
- {
-
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- List<?> r = client.get_slice(key, parent, predicate, state.settings.command.consistencyLevel);
- return r != null && r.size() > 0;
- }
-
- @Override
- public String key()
- {
- return new String(key.array());
- }
-
- @Override
- public int keyCount()
- {
- return 1;
- }
- });
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java
deleted file mode 100644
index 8c8ec31..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.util.ThriftClient;
-import org.apache.cassandra.thrift.*;
-import org.apache.cassandra.utils.ByteBufferUtil;
-import org.apache.cassandra.utils.FBUtilities;
-
-public class ThriftIndexedRangeSlicer extends Operation
-{
- public ThriftIndexedRangeSlicer(State state, long index)
- {
- super(state, index);
- if (!state.rowGen.isDeterministic() || !state.keyGen.isDeterministic())
- throw new IllegalStateException("Only run with a isDeterministic row/key generator");
- if (state.settings.columns.useSuperColumns || state.columnParents.size() != 1)
- throw new IllegalStateException("Does not support super columns");
- if (state.settings.columns.useTimeUUIDComparator)
- throw new IllegalStateException("Does not support TimeUUID column names");
- }
-
- public void run(final ThriftClient client) throws IOException
- {
-
- final SlicePredicate predicate = new SlicePredicate()
- .setSlice_range(new SliceRange(ByteBufferUtil.EMPTY_BYTE_BUFFER,
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- false, state.settings.columns.maxColumnsPerKey));
- final List<ByteBuffer> columns = generateColumnValues(getKey());
- final ColumnParent parent = state.columnParents.get(0);
-
- 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);
- byte[] minKey = new byte[0];
- final List<KeySlice>[] results = new List[1];
- do
- {
-
- final boolean first = minKey.length == 0;
- final IndexClause clause = new IndexClause(Arrays.asList(expression),
- ByteBuffer.wrap(minKey),
- state.settings.command.keysAtOnce);
-
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- results[0] = client.get_indexed_slices(parent, clause, predicate, state.settings.command.consistencyLevel);
- return !first || results[0].size() > 0;
- }
-
- @Override
- public String key()
- {
- return new String(value.array());
- }
-
- @Override
- public int keyCount()
- {
- return results[0].size();
- }
- });
-
- minKey = getNextMinKey(minKey, results[0]);
-
- } while (results[0].size() > 0);
- }
-
- /**
- * Get maximum key from keySlice list
- * @param slices list of the KeySlice objects
- * @return maximum key value of the list
- */
- private static byte[] getNextMinKey(byte[] cur, List<KeySlice> slices)
- {
- // find max
- for (KeySlice slice : slices)
- if (FBUtilities.compareUnsigned(cur, slice.getKey()) < 0)
- cur = slice.getKey();
-
- // increment
- for (int i = 0 ; i < cur.length ; i++)
- if (++cur[i] != 0)
- break;
- return cur;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java
deleted file mode 100644
index 7077a95..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.cassandra.db.marshal.TimeUUIDType;
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.util.ThriftClient;
-import org.apache.cassandra.thrift.*;
-import org.apache.cassandra.utils.FBUtilities;
-import org.apache.cassandra.utils.UUIDGen;
-
-public final class ThriftInserter extends Operation
-{
-
- public ThriftInserter(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
- final ByteBuffer key = getKey();
- final List<Column> columns = generateColumns(key);
-
- Map<String, List<Mutation>> row;
- if (!state.settings.columns.useSuperColumns)
- {
- List<Mutation> mutations = new ArrayList<>(columns.size());
- for (Column c : columns)
- {
- ColumnOrSuperColumn column = new ColumnOrSuperColumn().setColumn(c);
- mutations.add(new Mutation().setColumn_or_supercolumn(column));
- }
- row = Collections.singletonMap(state.type.table, mutations);
- }
- else
- {
- List<Mutation> mutations = new ArrayList<>(state.columnParents.size());
- for (ColumnParent parent : state.columnParents)
- {
- final SuperColumn s = new SuperColumn(parent.bufferForSuper_column(), columns);
- final ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setSuper_column(s);
- mutations.add(new Mutation().setColumn_or_supercolumn(cosc));
- }
- row = Collections.singletonMap(state.settings.command.type.supertable, mutations);
- }
-
- final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
-
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- client.batch_mutate(record, state.settings.command.consistencyLevel);
- return true;
- }
-
- @Override
- public String key()
- {
- return new String(key.array());
- }
-
- @Override
- public int keyCount()
- {
- return 1;
- }
- });
- }
-
- protected List<Column> generateColumns(ByteBuffer key)
- {
- final List<ByteBuffer> values = generateColumnValues(key);
- final List<Column> columns = new ArrayList<>(values.size());
-
- if (state.settings.columns.useTimeUUIDComparator)
- for (int i = 0 ; i < values.size() ; i++)
- new Column(TimeUUIDType.instance.decompose(UUIDGen.getTimeUUID()));
- else
- // 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(state.settings.columns.names.get(i)));
-
- for (int i = 0 ; i < values.size() ; i++)
- columns.get(i)
- .setValue(values.get(i))
- .setTimestamp(FBUtilities.timestampMicros());
-
- return columns;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java
deleted file mode 100644
index d8e0117..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.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;
-import org.apache.cassandra.thrift.ColumnParent;
-import org.apache.cassandra.thrift.SlicePredicate;
-import org.apache.cassandra.thrift.SliceRange;
-import org.apache.cassandra.utils.ByteBufferUtil;
-
-
-public final class ThriftMultiGetter extends Operation
-{
-
- public ThriftMultiGetter(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
-
- final SlicePredicate predicate = new SlicePredicate().setSlice_range(
- new SliceRange(
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- false,
- state.settings.columns.maxColumnsPerKey
- )
- );
-
- final List<ByteBuffer> keys = getKeys(state.settings.command.keysAtOnce);
-
- for (final ColumnParent parent : state.columnParents)
- {
- timeWithRetry(new RunOp()
- {
- int count;
- @Override
- public boolean run() throws Exception
- {
- return (count = client.multiget_slice(keys, parent, predicate, state.settings.command.consistencyLevel).size()) != 0;
- }
-
- @Override
- public String key()
- {
- return keys.toString();
- }
-
- @Override
- public int keyCount()
- {
- return count;
- }
- });
- }
- }
-
-}
[05/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java
deleted file mode 100644
index 021c4e8..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.util.ThriftClient;
-import org.apache.cassandra.thrift.ColumnParent;
-import org.apache.cassandra.thrift.KeyRange;
-import org.apache.cassandra.thrift.SlicePredicate;
-import org.apache.cassandra.thrift.SliceRange;
-import org.apache.cassandra.utils.ByteBufferUtil;
-
-public final class ThriftRangeSlicer extends Operation
-{
-
- public ThriftRangeSlicer(State state, long index)
- {
- super(state, index);
- }
-
- @Override
- public void run(final ThriftClient client) throws IOException
- {
- final SlicePredicate predicate = new SlicePredicate()
- .setSlice_range(
- new SliceRange(
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- false,
- state.settings.columns.maxColumnsPerKey
- )
- );
-
- final ByteBuffer start = getKey();
- final KeyRange range =
- new KeyRange(state.settings.columns.maxColumnsPerKey)
- .setStart_key(start)
- .setEnd_key(ByteBufferUtil.EMPTY_BYTE_BUFFER)
- .setCount(state.settings.command.keysAtOnce);
-
- for (final ColumnParent parent : state.columnParents)
- {
- timeWithRetry(new RunOp()
- {
- private int count = 0;
- @Override
- public boolean run() throws Exception
- {
- return (count = client.get_range_slices(parent, predicate, range, state.settings.command.consistencyLevel).size()) != 0;
- }
-
- @Override
- public String key()
- {
- return new String(range.bufferForStart_key().array());
- }
-
- @Override
- public int keyCount()
- {
- return count;
- }
- });
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java
deleted file mode 100644
index dccf469..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.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;
-import org.apache.cassandra.thrift.ColumnOrSuperColumn;
-import org.apache.cassandra.thrift.ColumnParent;
-import org.apache.cassandra.thrift.SlicePredicate;
-import org.apache.cassandra.thrift.SuperColumn;
-
-public final class ThriftReader extends Operation
-{
-
- public ThriftReader(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
- final SlicePredicate predicate = slicePredicate();
- final ByteBuffer key = getKey();
- final List<ByteBuffer> expect = state.rowGen.isDeterministic() ? generateColumnValues(key) : null;
- for (final ColumnParent parent : state.columnParents)
- {
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- List<ColumnOrSuperColumn> 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())
- return false;
- for (int i = 0 ; i < row.size() ; i++)
- if (!row.get(i).getColumn().bufferForValue().equals(expect.get(i)))
- return false;
- }
- else
- {
- for (ColumnOrSuperColumn col : row)
- {
- SuperColumn superColumn = col.getSuper_column();
- if (superColumn.getColumns().size() != expect.size())
- return false;
- for (int i = 0 ; i < expect.size() ; i++)
- if (!superColumn.getColumns().get(i).bufferForValue().equals(expect.get(i)))
- return false;
- }
- }
- return true;
- }
-
- @Override
- public String key()
- {
- return new String(key.array());
- }
-
- @Override
- public int keyCount()
- {
- return 1;
- }
- });
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
new file mode 100644
index 0000000..f794e75
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
@@ -0,0 +1,84 @@
+package org.apache.cassandra.stress.operations.predefined;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+
+public class CqlCounterAdder extends CqlOperation<Integer>
+{
+
+ final Distribution counteradd;
+ public CqlCounterAdder(DistributionFactory counteradd, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_WRITE, timer, generator, settings);
+ this.counteradd = counteradd.get();
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ String counterCF = isCql2() ? type.table : "Counter3";
+
+ StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(counterCF));
+
+ if (isCql2())
+ query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
+
+ query.append(" SET ");
+
+ // TODO : increment distribution subset of columns
+ for (int i = 0; i < settings.columns.maxColumnsPerKey; i++)
+ {
+ if (i > 0)
+ query.append(",");
+
+ query.append('C').append(i).append("=C").append(i).append("+?");
+ }
+ query.append(" WHERE KEY=?");
+ return query.toString();
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ final List<Object> list = new ArrayList<>();
+ for (int i = 0; i < settings.columns.maxColumnsPerKey; i++)
+ list.add(counteradd.next());
+ list.add(ByteBuffer.wrap(key));
+ return list;
+ }
+
+ @Override
+ protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ return new CqlRunOpAlwaysSucceed(client, query, queryId, params, key, 1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
new file mode 100644
index 0000000..94c8faf
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
@@ -0,0 +1,74 @@
+package org.apache.cassandra.stress.operations.predefined;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+
+public class CqlCounterGetter extends CqlOperation<Integer>
+{
+
+ public CqlCounterGetter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_READ, timer, generator, settings);
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ return Collections.<Object>singletonList(ByteBuffer.wrap(key));
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ StringBuilder query = new StringBuilder("SELECT ");
+
+ // TODO: obey slice/noslice option (instead of always slicing)
+ if (isCql2())
+ query.append("FIRST ").append(settings.columns.maxColumnsPerKey).append(" ''..''");
+ else
+ query.append("*");
+
+ String counterCF = isCql2() ? type.table : "Counter3";
+
+ query.append(" FROM ").append(wrapInQuotesIfRequired(counterCF));
+
+ if (isCql2())
+ query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
+
+ return query.append(" WHERE KEY=?").toString();
+ }
+
+ @Override
+ protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ return new CqlRunOpTestNonEmpty(client, query, queryId, params, key);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
new file mode 100644
index 0000000..c422f2b
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
@@ -0,0 +1,79 @@
+package org.apache.cassandra.stress.operations.predefined;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.utils.UUIDGen;
+
+public class CqlInserter extends CqlOperation<Integer>
+{
+
+ public CqlInserter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.WRITE, timer, generator, settings);
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(type.table));
+
+ if (isCql2())
+ query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
+
+ query.append(" SET ");
+
+ for (int i = 0 ; i < settings.columns.maxColumnsPerKey ; i++)
+ {
+ if (i > 0)
+ query.append(',');
+
+ query.append(wrapInQuotesIfRequired(settings.columns.namestrs.get(i))).append(" = ?");
+ }
+
+ query.append(" WHERE KEY=?");
+ return query.toString();
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ final ArrayList<Object> queryParams = new ArrayList<>();
+ List<ByteBuffer> values = getColumnValues();
+ queryParams.addAll(values);
+ queryParams.add(ByteBuffer.wrap(key));
+ return queryParams;
+ }
+
+ @Override
+ protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ return new CqlRunOpAlwaysSucceed(client, query, queryId, params, key, 1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
new file mode 100644
index 0000000..0264cd1
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
@@ -0,0 +1,714 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.google.common.base.Function;
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.StressMetrics;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.ConnectionStyle;
+import org.apache.cassandra.stress.settings.CqlVersion;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.Compression;
+import org.apache.cassandra.thrift.CqlResult;
+import org.apache.cassandra.thrift.CqlRow;
+import org.apache.cassandra.thrift.ThriftConversion;
+import org.apache.cassandra.transport.SimpleClient;
+import org.apache.cassandra.transport.messages.ResultMessage;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.thrift.TException;
+
+public abstract class CqlOperation<V> extends PredefinedOperation
+{
+
+ protected abstract List<Object> getQueryParameters(byte[] key);
+ protected abstract String buildQuery();
+ protected abstract CqlRunOp<V> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key);
+
+ public CqlOperation(Command type, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(type, timer, generator, settings);
+ if (settings.columns.variableColumnCount)
+ throw new IllegalStateException("Variable column counts are not implemented for CQL");
+ }
+
+ protected CqlRunOp<V> run(final ClientWrapper client, final List<Object> queryParams, final ByteBuffer key) throws IOException
+ {
+ final CqlRunOp<V> op;
+ if (settings.mode.style == ConnectionStyle.CQL_PREPARED)
+ {
+ final Object id;
+ Object idobj = getCqlCache();
+ if (idobj == null)
+ {
+ try
+ {
+ id = client.createPreparedStatement(buildQuery());
+ } catch (TException e)
+ {
+ throw new RuntimeException(e);
+ }
+ storeCqlCache(id);
+ }
+ else
+ id = idobj;
+
+ op = buildRunOp(client, null, id, queryParams, key);
+ }
+ else
+ {
+ final String query;
+ Object qobj = getCqlCache();
+ if (qobj == null)
+ storeCqlCache(query = buildQuery());
+ else
+ query = qobj.toString();
+
+ op = buildRunOp(client, query, null, queryParams, key);
+ }
+
+ timeWithRetry(op);
+ return op;
+ }
+
+ protected void run(final ClientWrapper client) throws IOException
+ {
+ final byte[] key = getKey().array();
+ final List<Object> queryParams = getQueryParameters(key);
+ run(client, queryParams, ByteBuffer.wrap(key));
+ }
+
+ // Classes to process Cql results
+
+ // Always succeeds so long as the query executes without error; provides a keyCount to increment on instantiation
+ protected final class CqlRunOpAlwaysSucceed extends CqlRunOp<Integer>
+ {
+
+ final int keyCount;
+
+ protected CqlRunOpAlwaysSucceed(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key, int keyCount)
+ {
+ super(client, query, queryId, RowCountHandler.INSTANCE, params, key);
+ this.keyCount = keyCount;
+ }
+
+ @Override
+ public boolean validate(Integer result)
+ {
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return keyCount;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return keyCount;
+ }
+ }
+
+ // Succeeds so long as the result set is nonempty, and the query executes without error
+ protected final class CqlRunOpTestNonEmpty extends CqlRunOp<Integer>
+ {
+
+ protected CqlRunOpTestNonEmpty(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ super(client, query, queryId, RowCountHandler.INSTANCE, params, key);
+ }
+
+ @Override
+ public boolean validate(Integer result)
+ {
+ return result > 0;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return result;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return result;
+ }
+ }
+
+ // Requires a custom validate() method, but fetches and stores the keys from the result set for further processing
+ protected abstract class CqlRunOpFetchKeys extends CqlRunOp<byte[][]>
+ {
+
+ protected CqlRunOpFetchKeys(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ super(client, query, queryId, KeysHandler.INSTANCE, params, key);
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return result.length;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return result.length;
+ }
+ }
+
+ protected final class CqlRunOpMatchResults extends CqlRunOp<ByteBuffer[][]>
+ {
+
+ final List<List<ByteBuffer>> 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<Object> params, ByteBuffer key, List<List<ByteBuffer>> expect)
+ {
+ super(client, query, queryId, RowsHandler.INSTANCE, params, key);
+ this.expect = expect;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return result == null ? 0 : result.length;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return result == null ? 0 : result.length;
+ }
+
+ public boolean validate(ByteBuffer[][] result)
+ {
+ if (result.length != expect.size())
+ return false;
+ for (int i = 0 ; i < result.length ; i++)
+ if (expect.get(i) != null && !expect.get(i).equals(Arrays.asList(result[i])))
+ return false;
+ return true;
+ }
+ }
+
+ // Cql
+ protected abstract class CqlRunOp<V> implements RunOp
+ {
+
+ final ClientWrapper client;
+ final String query;
+ final Object queryId;
+ final List<Object> params;
+ final ByteBuffer key;
+ final ResultHandler<V> handler;
+ V result;
+
+ private CqlRunOp(ClientWrapper client, String query, Object queryId, ResultHandler<V> handler, List<Object> params, ByteBuffer key)
+ {
+ this.client = client;
+ this.query = query;
+ this.queryId = queryId;
+ this.handler = handler;
+ this.params = params;
+ this.key = key;
+ }
+
+ @Override
+ public boolean run() throws Exception
+ {
+ return queryId != null
+ ? validate(result = client.execute(queryId, key, params, handler))
+ : validate(result = client.execute(query, key, params, handler));
+ }
+
+ public abstract boolean validate(V result);
+
+ }
+
+
+ /// LOTS OF WRAPPING/UNWRAPPING NONSENSE
+
+
+ @Override
+ public void run(final ThriftClient client) throws IOException
+ {
+ run(wrap(client));
+ }
+
+ @Override
+ public void run(SimpleClient client) throws IOException
+ {
+ run(wrap(client));
+ }
+
+ @Override
+ public void run(JavaDriverClient client) throws IOException
+ {
+ run(wrap(client));
+ }
+
+ public ClientWrapper wrap(ThriftClient client)
+ {
+ return isCql3()
+ ? new Cql3CassandraClientWrapper(client)
+ : new Cql2CassandraClientWrapper(client);
+
+ }
+
+ public ClientWrapper wrap(JavaDriverClient client)
+ {
+ return new JavaDriverWrapper(client);
+ }
+
+ public ClientWrapper wrap(SimpleClient client)
+ {
+ return new SimpleClientWrapper(client);
+ }
+
+ protected interface ClientWrapper
+ {
+ Object createPreparedStatement(String cqlQuery) throws TException;
+ <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
+ <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
+ }
+
+ private final class JavaDriverWrapper implements ClientWrapper
+ {
+ final JavaDriverClient client;
+ private JavaDriverWrapper(JavaDriverClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ String formattedQuery = formatCqlQuery(query, queryParams, isCql3());
+ return handler.javaDriverHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ return handler.javaDriverHandler().apply(
+ client.executePrepared(
+ (PreparedStatement) preparedStatementId,
+ queryParams,
+ ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery)
+ {
+ return client.prepare(cqlQuery);
+ }
+ }
+
+ private final class SimpleClientWrapper implements ClientWrapper
+ {
+ final SimpleClient client;
+ private SimpleClientWrapper(SimpleClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ String formattedQuery = formatCqlQuery(query, queryParams, isCql3());
+ return handler.thriftHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ return handler.thriftHandler().apply(
+ client.executePrepared(
+ (byte[]) preparedStatementId,
+ toByteBufferParams(queryParams),
+ ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery)
+ {
+ return client.prepare(cqlQuery).statementId.bytes;
+ }
+ }
+
+ // client wrapper for Cql3
+ private final class Cql3CassandraClientWrapper implements ClientWrapper
+ {
+ final ThriftClient client;
+ private Cql3CassandraClientWrapper(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ String formattedQuery = formatCqlQuery(query, queryParams, true);
+ return handler.simpleNativeHandler().apply(
+ client.execute_cql3_query(formattedQuery, key, Compression.NONE, settings.command.consistencyLevel)
+ );
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ Integer id = (Integer) preparedStatementId;
+ return handler.simpleNativeHandler().apply(
+ client.execute_prepared_cql3_query(id, key, toByteBufferParams(queryParams), settings.command.consistencyLevel)
+ );
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery) throws TException
+ {
+ return client.prepare_cql3_query(cqlQuery, Compression.NONE);
+ }
+ }
+
+ // client wrapper for Cql2
+ private final class Cql2CassandraClientWrapper implements ClientWrapper
+ {
+ final ThriftClient client;
+ private Cql2CassandraClientWrapper(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ String formattedQuery = formatCqlQuery(query, queryParams, false);
+ return handler.simpleNativeHandler().apply(
+ client.execute_cql_query(formattedQuery, key, Compression.NONE)
+ );
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ Integer id = (Integer) preparedStatementId;
+ return handler.simpleNativeHandler().apply(
+ client.execute_prepared_cql_query(id, key, toByteBufferParams(queryParams))
+ );
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery) throws TException
+ {
+ return client.prepare_cql_query(cqlQuery, Compression.NONE);
+ }
+ }
+
+ // interface for building functions to standardise results from each client
+ protected static interface ResultHandler<V>
+ {
+ Function<ResultSet, V> javaDriverHandler();
+ Function<ResultMessage, V> thriftHandler();
+ Function<CqlResult, V> simpleNativeHandler();
+ }
+
+ protected static class RowCountHandler implements ResultHandler<Integer>
+ {
+ static final RowCountHandler INSTANCE = new RowCountHandler();
+
+ @Override
+ public Function<ResultSet, Integer> javaDriverHandler()
+ {
+ return new Function<ResultSet, Integer>()
+ {
+ @Override
+ public Integer apply(ResultSet rows)
+ {
+ if (rows == null)
+ return 0;
+ return rows.all().size();
+ }
+ };
+ }
+
+ @Override
+ public Function<ResultMessage, Integer> thriftHandler()
+ {
+ return new Function<ResultMessage, Integer>()
+ {
+ @Override
+ public Integer apply(ResultMessage result)
+ {
+ return result instanceof ResultMessage.Rows ? ((ResultMessage.Rows) result).result.size() : 0;
+ }
+ };
+ }
+
+ @Override
+ public Function<CqlResult, Integer> simpleNativeHandler()
+ {
+ return new Function<CqlResult, Integer>()
+ {
+
+ @Override
+ public Integer apply(CqlResult result)
+ {
+ switch (result.getType())
+ {
+ case ROWS:
+ return result.getRows().size();
+ default:
+ return 1;
+ }
+ }
+ };
+ }
+
+ }
+
+ // Processes results from each client into an array of all key bytes returned
+ protected static final class RowsHandler implements ResultHandler<ByteBuffer[][]>
+ {
+ static final RowsHandler INSTANCE = new RowsHandler();
+
+ @Override
+ public Function<ResultSet, ByteBuffer[][]> javaDriverHandler()
+ {
+ return new Function<ResultSet, ByteBuffer[][]>()
+ {
+
+ @Override
+ public ByteBuffer[][] apply(ResultSet result)
+ {
+ if (result == null)
+ return new ByteBuffer[0][];
+ List<Row> rows = result.all();
+
+ ByteBuffer[][] r = new ByteBuffer[rows.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ {
+ Row row = rows.get(i);
+ r[i] = new ByteBuffer[row.getColumnDefinitions().size()];
+ for (int j = 0 ; j < row.getColumnDefinitions().size() ; j++)
+ r[i][j] = row.getBytes(j);
+ }
+ return r;
+ }
+ };
+ }
+
+ @Override
+ public Function<ResultMessage, ByteBuffer[][]> thriftHandler()
+ {
+ return new Function<ResultMessage, ByteBuffer[][]>()
+ {
+
+ @Override
+ public ByteBuffer[][] apply(ResultMessage result)
+ {
+ if (!(result instanceof ResultMessage.Rows))
+ return new ByteBuffer[0][];
+
+ ResultMessage.Rows rows = ((ResultMessage.Rows) result);
+ ByteBuffer[][] r = new ByteBuffer[rows.result.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ {
+ List<ByteBuffer> row = rows.result.rows.get(i);
+ r[i] = new ByteBuffer[row.size()];
+ for (int j = 0 ; j < row.size() ; j++)
+ r[i][j] = row.get(j);
+ }
+ return r;
+ }
+ };
+ }
+
+ @Override
+ public Function<CqlResult, ByteBuffer[][]> simpleNativeHandler()
+ {
+ return new Function<CqlResult, ByteBuffer[][]>()
+ {
+
+ @Override
+ public ByteBuffer[][] apply(CqlResult result)
+ {
+ ByteBuffer[][] r = new ByteBuffer[result.getRows().size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ {
+ CqlRow row = result.getRows().get(i);
+ r[i] = new ByteBuffer[row.getColumns().size()];
+ for (int j = 0 ; j < r[i].length ; j++)
+ r[i][j] = ByteBuffer.wrap(row.getColumns().get(j).getValue());
+ }
+ return r;
+ }
+ };
+ }
+
+ }
+ // Processes results from each client into an array of all key bytes returned
+ protected static final class KeysHandler implements ResultHandler<byte[][]>
+ {
+ static final KeysHandler INSTANCE = new KeysHandler();
+
+ @Override
+ public Function<ResultSet, byte[][]> javaDriverHandler()
+ {
+ return new Function<ResultSet, byte[][]>()
+ {
+
+ @Override
+ public byte[][] apply(ResultSet result)
+ {
+
+ if (result == null)
+ return new byte[0][];
+ List<Row> rows = result.all();
+ byte[][] r = new byte[rows.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ r[i] = rows.get(i).getBytes(0).array();
+ return r;
+ }
+ };
+ }
+
+ @Override
+ public Function<ResultMessage, byte[][]> thriftHandler()
+ {
+ return new Function<ResultMessage, byte[][]>()
+ {
+
+ @Override
+ public byte[][] apply(ResultMessage result)
+ {
+ if (result instanceof ResultMessage.Rows)
+ {
+ ResultMessage.Rows rows = ((ResultMessage.Rows) result);
+ byte[][] r = new byte[rows.result.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ r[i] = rows.result.rows.get(i).get(0).array();
+ return r;
+ }
+ return null;
+ }
+ };
+ }
+
+ @Override
+ public Function<CqlResult, byte[][]> simpleNativeHandler()
+ {
+ return new Function<CqlResult, byte[][]>()
+ {
+
+ @Override
+ public byte[][] apply(CqlResult result)
+ {
+ byte[][] r = new byte[result.getRows().size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ r[i] = result.getRows().get(i).getKey();
+ return r;
+ }
+ };
+ }
+
+ }
+
+ private static String getUnQuotedCqlBlob(ByteBuffer term, boolean isCQL3)
+ {
+ return isCQL3
+ ? "0x" + ByteBufferUtil.bytesToHex(term)
+ : ByteBufferUtil.bytesToHex(term);
+ }
+
+ /**
+ * Constructs a CQL query string by replacing instances of the character
+ * '?', with the corresponding parameter.
+ *
+ * @param query base query string to format
+ * @param parms sequence of string query parameters
+ * @return formatted CQL query string
+ */
+ private static String formatCqlQuery(String query, List<Object> parms, boolean isCql3)
+ {
+ int marker, position = 0;
+ StringBuilder result = new StringBuilder();
+
+ if (-1 == (marker = query.indexOf('?')) || parms.size() == 0)
+ return query;
+
+ for (Object parm : parms)
+ {
+ result.append(query.substring(position, marker));
+ 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)))
+ break;
+ }
+
+ if (position < query.length())
+ result.append(query.substring(position));
+
+ return result.toString();
+ }
+
+ private static List<ByteBuffer> toByteBufferParams(List<Object> params)
+ {
+ List<ByteBuffer> 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 settings.mode.cqlVersion == CqlVersion.CQL3
+ ? "\"" + string + "\""
+ : string;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
new file mode 100644
index 0000000..3a7f75a
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
@@ -0,0 +1,87 @@
+package org.apache.cassandra.stress.operations.predefined;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public class CqlReader extends CqlOperation<ByteBuffer[][]>
+{
+
+ public CqlReader(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.READ, timer, generator, settings);
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ StringBuilder query = new StringBuilder("SELECT ");
+
+ if (settings.columns.slice)
+ {
+ if (isCql2())
+ query.append("FIRST ").append(settings.columns.maxColumnsPerKey).append(" ''..''");
+ else
+ query.append("*");
+ }
+ else
+ {
+ for (int i = 0; i < settings.columns.maxColumnsPerKey ; i++)
+ {
+ if (i > 0)
+ query.append(",");
+ query.append(wrapInQuotesIfRequired(settings.columns.namestrs.get(i)));
+ }
+ }
+
+ query.append(" FROM ").append(wrapInQuotesIfRequired(type.table));
+
+ if (isCql2())
+ query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
+ query.append(" WHERE KEY=?");
+ return query.toString();
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ return Collections.<Object>singletonList(ByteBuffer.wrap(key));
+ }
+
+ @Override
+ protected CqlRunOp<ByteBuffer[][]> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ List<ByteBuffer> expectRow = getColumnValues();
+ return new CqlRunOpMatchResults(client, query, queryId, params, key, Arrays.asList(expectRow));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
new file mode 100644
index 0000000..7f6412b
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
@@ -0,0 +1,248 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+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.Operation;
+import org.apache.cassandra.stress.StressMetrics;
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.DistributionFixed;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.Row;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.CqlVersion;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.ColumnParent;
+import org.apache.cassandra.thrift.SlicePredicate;
+import org.apache.cassandra.thrift.SliceRange;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public abstract class PredefinedOperation extends Operation
+{
+ public final Command type;
+ private final Distribution columnCount;
+ private Object cqlCache;
+
+ public PredefinedOperation(Command type, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(timer, generator, settings, new DistributionFixed(1));
+ this.type = type;
+ this.columnCount = settings.columns.countDistribution.get();
+ }
+
+ public boolean isCql3()
+ {
+ return settings.mode.cqlVersion == CqlVersion.CQL3;
+ }
+ public boolean isCql2()
+ {
+ return settings.mode.cqlVersion == CqlVersion.CQL2;
+ }
+ public Object getCqlCache()
+ {
+ return cqlCache;
+ }
+ public void storeCqlCache(Object val)
+ {
+ cqlCache = val;
+ }
+
+ protected ByteBuffer getKey()
+ {
+ return (ByteBuffer) partitions.get(0).getPartitionKey(0);
+ }
+
+ final class ColumnSelection
+ {
+ final int[] indices;
+ final int lb, ub;
+ private ColumnSelection(int[] indices, int lb, int ub)
+ {
+ this.indices = indices;
+ this.lb = lb;
+ this.ub = ub;
+ }
+
+ public <V> List<V> select(List<V> in)
+ {
+ List<V> out = new ArrayList<>();
+ if (indices != null)
+ {
+ for (int i : indices)
+ out.add(in.get(i));
+ }
+ else
+ {
+ out.addAll(in.subList(lb, ub));
+ }
+ return out;
+ }
+
+ int count()
+ {
+ return indices != null ? indices.length : ub - lb;
+ }
+
+ SlicePredicate predicate()
+ {
+ final SlicePredicate predicate = new SlicePredicate();
+ if (indices == null)
+ {
+ predicate.setSlice_range(new SliceRange()
+ .setStart(settings.columns.names.get(lb))
+ .setFinish(new byte[] {})
+ .setReversed(false)
+ .setCount(count())
+ );
+ }
+ else
+ predicate.setColumn_names(select(settings.columns.names));
+ return predicate;
+
+ }
+ }
+
+ public String toString()
+ {
+ return type.toString();
+ }
+
+ ColumnSelection select()
+ {
+ if (settings.columns.slice)
+ {
+ int count = (int) columnCount.next();
+ int start;
+ if (count == settings.columns.maxColumnsPerKey)
+ start = 0;
+ else
+ start = 1 + ThreadLocalRandom.current().nextInt(settings.columns.maxColumnsPerKey - count);
+ return new ColumnSelection(null, start, start + count);
+ }
+
+ int count = (int) columnCount.next();
+ int totalCount = settings.columns.names.size();
+ if (count == settings.columns.names.size())
+ return new ColumnSelection(null, 0, count);
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ int[] indices = new int[count];
+ int c = 0, o = 0;
+ while (c < count && count + o < totalCount)
+ {
+ int leeway = totalCount - (count + o);
+ int spreadover = count - c;
+ o += Math.round(rnd.nextDouble() * (leeway / (double) spreadover));
+ indices[c] = o + c;
+ c++;
+ }
+ while (c < count)
+ {
+ indices[c] = o + c;
+ c++;
+ }
+ return new ColumnSelection(indices, 0, 0);
+ }
+
+ protected List<ByteBuffer> getColumnValues()
+ {
+ return getColumnValues(new ColumnSelection(null, 0, settings.columns.names.size()));
+ }
+
+ protected List<ByteBuffer> getColumnValues(ColumnSelection columns)
+ {
+ Row row = partitions.get(0).iterator(1).batch(1f).iterator().next();
+ ByteBuffer[] r = new ByteBuffer[columns.count()];
+ int c = 0;
+ if (columns.indices != null)
+ for (int i : columns.indices)
+ r[c++] = (ByteBuffer) row.get(i);
+ else
+ for (int i = columns.lb ; i < columns.ub ; i++)
+ r[c++] = (ByteBuffer) row.get(i);
+ return Arrays.asList(r);
+ }
+
+ public static Operation operation(Command type, Timer timer, PartitionGenerator generator, StressSettings settings, DistributionFactory counteradd)
+ {
+ switch (type)
+ {
+ case READ:
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftReader(timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlReader(timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+
+ case COUNTER_READ:
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftCounterGetter(timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlCounterGetter(timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ case WRITE:
+
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftInserter(timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlInserter(timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ case COUNTER_WRITE:
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftCounterAdder(counteradd, timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlCounterAdder(counteradd, timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ throw new UnsupportedOperationException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterAdder.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterAdder.java
new file mode 100644
index 0000000..ee766c3
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterAdder.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.*;
+
+public class ThriftCounterAdder extends PredefinedOperation
+{
+
+ final Distribution counteradd;
+ public ThriftCounterAdder(DistributionFactory counteradd, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_WRITE, timer, generator, settings);
+ this.counteradd = counteradd.get();
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ List<CounterColumn> columns = new ArrayList<>();
+ for (ByteBuffer name : select().select(settings.columns.names))
+ columns.add(new CounterColumn(name, counteradd.next()));
+
+ List<Mutation> mutations = new ArrayList<>(columns.size());
+ for (CounterColumn c : columns)
+ {
+ ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setCounter_column(c);
+ mutations.add(new Mutation().setColumn_or_supercolumn(cosc));
+ }
+ Map<String, List<Mutation>> row = Collections.singletonMap(type.table, mutations);
+
+ final ByteBuffer key = getKey();
+ final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
+
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ client.batch_mutate(record, settings.command.consistencyLevel);
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterGetter.java
new file mode 100644
index 0000000..10c6aab
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterGetter.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+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.SlicePredicate;
+
+public class ThriftCounterGetter extends PredefinedOperation
+{
+ public ThriftCounterGetter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_READ, timer, generator, settings);
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ final SlicePredicate predicate = select().predicate();
+ final ByteBuffer key = getKey();
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ List<?> r = client.get_slice(key, new ColumnParent(type.table), predicate, settings.command.consistencyLevel);
+ return r != null && r.size() > 0;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
new file mode 100644
index 0000000..5c2acfe
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cassandra.db.marshal.TimeUUIDType;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.*;
+import org.apache.cassandra.utils.FBUtilities;
+import org.apache.cassandra.utils.UUIDGen;
+
+public final class ThriftInserter extends PredefinedOperation
+{
+
+ public ThriftInserter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.WRITE, timer, generator, settings);
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ final ByteBuffer key = getKey();
+ final List<Column> columns = getColumns();
+
+ List<Mutation> mutations = new ArrayList<>(columns.size());
+ for (Column c : columns)
+ {
+ ColumnOrSuperColumn column = new ColumnOrSuperColumn().setColumn(c);
+ mutations.add(new Mutation().setColumn_or_supercolumn(column));
+ }
+ Map<String, List<Mutation>> row = Collections.singletonMap(type.table, mutations);
+
+ final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
+
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ client.batch_mutate(record, settings.command.consistencyLevel);
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+ protected List<Column> getColumns()
+ {
+ final ColumnSelection selection = select();
+ final List<ByteBuffer> values = getColumnValues(selection);
+ final List<Column> columns = new ArrayList<>(values.size());
+ final List<ByteBuffer> names = select().select(settings.columns.names);
+ for (int i = 0 ; i < values.size() ; i++)
+ columns.add(new Column(names.get(i))
+ .setValue(values.get(i))
+ .setTimestamp(FBUtilities.timestampMicros()));
+ return columns;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftReader.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftReader.java
new file mode 100644
index 0000000..276d8c5
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftReader.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.ColumnOrSuperColumn;
+import org.apache.cassandra.thrift.ColumnParent;
+import org.apache.cassandra.thrift.SlicePredicate;
+import org.apache.cassandra.thrift.SuperColumn;
+
+public final class ThriftReader extends PredefinedOperation
+{
+
+ public ThriftReader(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.READ, timer, generator, settings);
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ final ColumnSelection select = select();
+ final ByteBuffer key = getKey();
+ final List<ByteBuffer> expect = getColumnValues(select);
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ List<ColumnOrSuperColumn> row = client.get_slice(key, new ColumnParent(type.table), select.predicate(), settings.command.consistencyLevel);
+ if (expect == null)
+ return !row.isEmpty();
+ if (row == null)
+ return false;
+ if (row.size() != expect.size())
+ return false;
+ for (int i = 0 ; i < row.size() ; i++)
+ if (!row.get(i).getColumn().bufferForValue().equals(expect.get(i)))
+ return false;
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaInsert.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaInsert.java b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaInsert.java
new file mode 100644
index 0000000..7c5efac
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaInsert.java
@@ -0,0 +1,144 @@
+package org.apache.cassandra.stress.operations.userdefined;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.datastax.driver.core.BatchStatement;
+import com.datastax.driver.core.BoundStatement;
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.Statement;
+import org.apache.cassandra.db.ConsistencyLevel;
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.Partition;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.RatioDistribution;
+import org.apache.cassandra.stress.generate.Row;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.settings.ValidationType;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+
+public class SchemaInsert extends SchemaStatement
+{
+
+ private final BatchStatement.Type batchType;
+ private final RatioDistribution perVisit;
+ private final RatioDistribution perBatch;
+
+ public SchemaInsert(Timer timer, PartitionGenerator generator, StressSettings settings, Distribution partitionCount, RatioDistribution perVisit, RatioDistribution perBatch, Integer thriftId, PreparedStatement statement, ConsistencyLevel cl, BatchStatement.Type batchType)
+ {
+ super(timer, generator, settings, partitionCount, statement, thriftId, cl, ValidationType.NOT_FAIL);
+ this.batchType = batchType;
+ this.perVisit = perVisit;
+ this.perBatch = perBatch;
+ }
+
+ private class JavaDriverRun extends Runner
+ {
+ final JavaDriverClient client;
+
+ private JavaDriverRun(JavaDriverClient client)
+ {
+ this.client = client;
+ }
+
+ public boolean run() throws Exception
+ {
+ Partition.RowIterator[] iterators = new Partition.RowIterator[partitions.size()];
+ for (int i = 0 ; i < iterators.length ; i++)
+ iterators[i] = partitions.get(i).iterator(perVisit.next());
+ List<BoundStatement> stmts = new ArrayList<>();
+ partitionCount = partitions.size();
+
+ boolean done;
+ do
+ {
+ done = true;
+ stmts.clear();
+ for (Partition.RowIterator iterator : iterators)
+ {
+ if (iterator.done())
+ continue;
+
+ for (Row row : iterator.batch(perBatch.next()))
+ stmts.add(bindRow(row));
+
+ done &= iterator.done();
+ }
+
+ rowCount += stmts.size();
+
+ Statement stmt;
+ if (stmts.size() == 1)
+ {
+ stmt = stmts.get(0);
+ }
+ else
+ {
+ BatchStatement batch = new BatchStatement(batchType);
+ batch.setConsistencyLevel(JavaDriverClient.from(cl));
+ batch.addAll(stmts);
+ stmt = batch;
+ }
+ validate(client.getSession().execute(stmt));
+
+ } while (!done);
+
+ return true;
+ }
+ }
+
+ private class ThriftRun extends Runner
+ {
+ final ThriftClient client;
+
+ private ThriftRun(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ public boolean run() throws Exception
+ {
+ Partition.RowIterator[] iterators = new Partition.RowIterator[partitions.size()];
+ for (int i = 0 ; i < iterators.length ; i++)
+ iterators[i] = partitions.get(i).iterator(perVisit.next());
+ partitionCount = partitions.size();
+
+ boolean done;
+ do
+ {
+ done = true;
+ for (Partition.RowIterator iterator : iterators)
+ {
+ if (iterator.done())
+ continue;
+
+ for (Row row : iterator.batch(perBatch.next()))
+ {
+ validate(client.execute_prepared_cql3_query(thriftId, iterator.partition().getToken(), thriftRowArgs(row), settings.command.consistencyLevel));
+ rowCount += 1;
+ }
+
+ done &= iterator.done();
+ }
+ } while (!done);
+
+ return true;
+ }
+ }
+
+ @Override
+ public void run(JavaDriverClient client) throws IOException
+ {
+ timeWithRetry(new JavaDriverRun(client));
+ }
+
+ @Override
+ public void run(ThriftClient client) throws IOException
+ {
+ timeWithRetry(new ThriftRun(client));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaQuery.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaQuery.java b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaQuery.java
new file mode 100644
index 0000000..9cec39b
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaQuery.java
@@ -0,0 +1,86 @@
+package org.apache.cassandra.stress.operations.userdefined;
+
+import java.io.IOException;
+
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.ResultSet;
+import org.apache.cassandra.db.ConsistencyLevel;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.OptionDistribution;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.settings.ValidationType;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.CqlResult;
+import org.apache.cassandra.thrift.ThriftConversion;
+
+public class SchemaQuery extends SchemaStatement
+{
+
+ public SchemaQuery(Timer timer, PartitionGenerator generator, StressSettings settings, Integer thriftId, PreparedStatement statement, ConsistencyLevel cl, ValidationType validationType)
+ {
+ super(timer, generator, settings, OptionDistribution.get("fixed(1)").get(), statement, thriftId, cl, validationType);
+ }
+
+ int execute(JavaDriverClient client) throws Exception
+ {
+ return client.getSession().execute(bindRandom(partitions.get(0))).all().size();
+ }
+
+ int execute(ThriftClient client) throws Exception
+ {
+ return client.execute_prepared_cql3_query(thriftId, partitions.get(0).getToken(), thriftRandomArgs(partitions.get(0)), ThriftConversion.toThrift(cl)).getRowsSize();
+ }
+
+ private class JavaDriverRun extends Runner
+ {
+ final JavaDriverClient client;
+
+ private JavaDriverRun(JavaDriverClient client)
+ {
+ this.client = client;
+ }
+
+ public boolean run() throws Exception
+ {
+ ResultSet rs = client.getSession().execute(bindRandom(partitions.get(0)));
+ validate(rs);
+ rowCount = rs.all().size();
+ partitionCount = Math.min(1, rowCount);
+ return true;
+ }
+ }
+
+ private class ThriftRun extends Runner
+ {
+ final ThriftClient client;
+
+ private ThriftRun(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ public boolean run() throws Exception
+ {
+ CqlResult rs = client.execute_prepared_cql3_query(thriftId, partitions.get(0).getToken(), thriftRandomArgs(partitions.get(0)), ThriftConversion.toThrift(cl));
+ validate(rs);
+ rowCount = rs.getRowsSize();
+ partitionCount = Math.min(1, rowCount);
+ return true;
+ }
+ }
+
+ @Override
+ public void run(JavaDriverClient client) throws IOException
+ {
+ timeWithRetry(new JavaDriverRun(client));
+ }
+
+ @Override
+ public void run(ThriftClient client) throws IOException
+ {
+ timeWithRetry(new ThriftRun(client));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaStatement.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaStatement.java b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaStatement.java
new file mode 100644
index 0000000..aac40c5
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaStatement.java
@@ -0,0 +1,164 @@
+package org.apache.cassandra.stress.operations.userdefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import com.datastax.driver.core.BoundStatement;
+import com.datastax.driver.core.ColumnDefinitions;
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.ResultSet;
+import org.apache.cassandra.db.ConsistencyLevel;
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.Partition;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.Row;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.settings.ValidationType;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.CqlResult;
+import org.apache.cassandra.transport.SimpleClient;
+
+public abstract class SchemaStatement extends Operation
+{
+
+ final PartitionGenerator generator;
+ private final PreparedStatement statement;
+ final Integer thriftId;
+ final ConsistencyLevel cl;
+ final ValidationType validationType;
+ private final int[] argumentIndex;
+ private final Object[] bindBuffer;
+ private final Object[][] randomBuffer;
+ private final Random random = new Random();
+
+ public SchemaStatement(Timer timer, PartitionGenerator generator, StressSettings settings, Distribution partitionCount,
+ PreparedStatement statement, Integer thriftId, ConsistencyLevel cl, ValidationType validationType)
+ {
+ super(timer, generator, settings, partitionCount);
+ this.generator = generator;
+ this.statement = statement;
+ this.thriftId = thriftId;
+ this.cl = cl;
+ this.validationType = validationType;
+ argumentIndex = new int[statement.getVariables().size()];
+ bindBuffer = new Object[argumentIndex.length];
+ randomBuffer = new Object[argumentIndex.length][argumentIndex.length];
+ int i = 0;
+ for (ColumnDefinitions.Definition definition : statement.getVariables())
+ argumentIndex[i++] = generator.indexOf(definition.getName());
+ }
+
+ private int filLRandom(Partition partition)
+ {
+ int c = 0;
+ for (Row row : partition.iterator(randomBuffer.length).batch(1f))
+ {
+ Object[] randomRow = randomBuffer[c++];
+ for (int i = 0 ; i < argumentIndex.length ; i++)
+ randomRow[i] = row.get(argumentIndex[i]);
+ if (c >= randomBuffer.length)
+ break;
+ }
+ return c;
+ }
+
+ BoundStatement bindRandom(Partition partition)
+ {
+ int c = filLRandom(partition);
+ for (int i = 0 ; i < argumentIndex.length ; i++)
+ {
+ int argIndex = argumentIndex[i];
+ bindBuffer[i] = randomBuffer[argIndex < 0 ? 0 : random.nextInt(c)][i];
+ }
+ return statement.bind(bindBuffer);
+ }
+
+ BoundStatement bindRow(Row row)
+ {
+ for (int i = 0 ; i < argumentIndex.length ; i++)
+ bindBuffer[i] = row.get(argumentIndex[i]);
+ return statement.bind(bindBuffer);
+ }
+
+ List<ByteBuffer> thriftRowArgs(Row row)
+ {
+ List<ByteBuffer> args = new ArrayList<>();
+ for (int i : argumentIndex)
+ args.add(generator.convert(i, row.get(i)));
+ return args;
+ }
+
+ List<ByteBuffer> thriftRandomArgs(Partition partition)
+ {
+ List<ByteBuffer> args = new ArrayList<>();
+ int c = filLRandom(partition);
+ for (int i = 0 ; i < argumentIndex.length ; i++)
+ {
+ int argIndex = argumentIndex[i];
+ args.add(generator.convert(argIndex, randomBuffer[argIndex < 0 ? 0 : random.nextInt(c)][i]));
+ }
+ return args;
+ }
+
+ void validate(ResultSet rs)
+ {
+ switch (validationType)
+ {
+ case NOT_FAIL:
+ return;
+ case NON_ZERO:
+ if (rs.all().size() == 0)
+ throw new IllegalStateException("Expected non-zero results");
+ break;
+ default:
+ throw new IllegalStateException("Unsupported validation type");
+ }
+ }
+
+ void validate(CqlResult rs)
+ {
+ switch (validationType)
+ {
+ case NOT_FAIL:
+ return;
+ case NON_ZERO:
+ if (rs.getRowsSize() == 0)
+ throw new IllegalStateException("Expected non-zero results");
+ break;
+ default:
+ throw new IllegalStateException("Unsupported validation type");
+ }
+ }
+
+ @Override
+ public void run(SimpleClient client) throws IOException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ abstract class Runner implements RunOp
+ {
+ int partitionCount;
+ int rowCount;
+
+ @Override
+ public int partitionCount()
+ {
+ return partitionCount;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return rowCount;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/Command.java
----------------------------------------------------------------------
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 ac10014..7138cbb 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/Command.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/Command.java
@@ -41,19 +41,6 @@ public enum Command
"Interleaving of any basic commands, with configurable ratio and distribution - the cluster must first be populated by a write test",
CommandCategory.MIXED
),
- RANGE_SLICE(false, "Standard1", "Super1",
- "Range slice queries - the cluster must first be populated by a write test",
- CommandCategory.MULTI
- ),
- INDEXED_RANGE_SLICE(false, "Standard1", "Super1",
- "Range slice queries through a secondary index. The cluster must first be populated by a write test, with indexing enabled.",
- CommandCategory.BASIC
- ),
- READ_MULTI(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
- ),
COUNTER_WRITE(true, "Counter1", "SuperCounter1",
"counter_add",
"Multiple concurrent updates of counters.",
@@ -64,6 +51,10 @@ public enum Command
"Multiple concurrent reads of counters. The cluster must first be populated by a counterwrite test.",
CommandCategory.BASIC
),
+ USER(true, null, null,
+ "Interleaving of user provided queries, with configurable ratio and distribution",
+ CommandCategory.USER
+ ),
HELP(false, null, null, "-?", "Print help for a command or option", null),
PRINT(false, null, null, "Inspect the output of a distribution definition", null),
@@ -136,11 +127,12 @@ public enum Command
}
switch (category)
{
+ case USER:
+ return SettingsCommandUser.helpPrinter();
case BASIC:
- case MULTI:
- return SettingsCommand.helpPrinter(this);
+ return SettingsCommandPreDefined.helpPrinter(this);
case MIXED:
- return SettingsCommandMixed.helpPrinter();
+ return SettingsCommandPreDefinedMixed.helpPrinter();
}
throw new AssertionError();
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java b/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java
index 4372f59..e9dd946 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java
@@ -24,6 +24,6 @@ package org.apache.cassandra.stress.settings;
public enum CommandCategory
{
BASIC,
- MULTI,
- MIXED
+ MIXED,
+ USER
}
[07/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionOffsetApache.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionOffsetApache.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionOffsetApache.java
new file mode 100644
index 0000000..b0e41eb
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionOffsetApache.java
@@ -0,0 +1,80 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.commons.math3.distribution.AbstractRealDistribution;
+
+public class DistributionOffsetApache extends Distribution
+{
+
+ final AbstractRealDistribution delegate;
+ final long min, delta;
+
+ public DistributionOffsetApache(AbstractRealDistribution delegate, long min, long max)
+ {
+ this.delegate = delegate;
+ this.min = min;
+ this.delta = max - min;
+ }
+
+ public void setSeed(long seed)
+ {
+ delegate.reseedRandomGenerator(seed);
+ }
+
+ @Override
+ public long next()
+ {
+ return offset(min, delta, delegate.sample());
+ }
+
+ public double nextDouble()
+ {
+ return offsetDouble(min, delta, delegate.sample());
+ }
+
+ @Override
+ public long inverseCumProb(double cumProb)
+ {
+ return offset(min, delta, delegate.inverseCumulativeProbability(cumProb));
+ }
+
+ private long offset(long min, long delta, double val)
+ {
+ long r = (long) val;
+ if (r < 0)
+ r = 0;
+ if (r > delta)
+ r = delta;
+ return min + r;
+ }
+
+ private double offsetDouble(long min, long delta, double r)
+ {
+ if (r < 0)
+ r = 0;
+ if (r > delta)
+ r = delta;
+ return min + r;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/Partition.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/Partition.java b/tools/stress/src/org/apache/cassandra/stress/generate/Partition.java
new file mode 100644
index 0000000..856d550
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/Partition.java
@@ -0,0 +1,343 @@
+package org.apache.cassandra.stress.generate;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Queue;
+import java.util.Random;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.BytesType;
+import org.apache.cassandra.stress.generate.values.Generator;
+
+// a partition is re-used to reduce garbage generation, as is its internal RowIterator
+public class Partition
+{
+
+ private long idseed;
+ private final Object[] partitionKey;
+ private final PartitionGenerator generator;
+ private final RowIterator iterator;
+
+ public Partition(PartitionGenerator generator)
+ {
+ this.generator = generator;
+ this.partitionKey = new Object[generator.partitionKey.size()];
+ if (generator.clusteringComponents.size() > 0)
+ iterator = new MultiRowIterator();
+ else
+ iterator = new SingleRowIterator();
+ }
+
+ void setSeed(long seed)
+ {
+ long idseed = 0;
+ for (int i = 0 ; i < partitionKey.length ; i++)
+ {
+ Generator generator = this.generator.partitionKey.get(i);
+ // set the partition key seed based on the current work item we're processing
+ generator.setSeed(seed);
+ Object key = generator.generate();
+ partitionKey[i] = key;
+ // then contribute this value to the data seed
+ idseed = seed(key, generator.type, idseed);
+ }
+ this.idseed = idseed;
+ }
+
+ public RowIterator iterator(double useChance)
+ {
+ iterator.reset(useChance, 0);
+ return iterator;
+ }
+
+ public RowIterator iterator(int targetCount)
+ {
+ iterator.reset(Double.NaN, targetCount);
+ return iterator;
+ }
+
+ class SingleRowIterator extends RowIterator
+ {
+ boolean done;
+
+ void reset(double useChance, int targetCount)
+ {
+ done = false;
+ }
+
+ public Iterable<Row> batch(double ratio)
+ {
+ if (done)
+ return Collections.emptyList();
+ for (int i = 0 ; i < row.row.length ; i++)
+ {
+ Generator gen = generator.valueComponents.get(i);
+ gen.setSeed(idseed);
+ row.row[i] = gen.generate();
+ }
+ done = true;
+ return Collections.singleton(row);
+ }
+
+ public boolean done()
+ {
+ return done;
+ }
+ }
+
+ public abstract class RowIterator
+ {
+ // we reuse the row object to save garbage
+ final Row row = new Row(partitionKey, new Object[generator.clusteringComponents.size() + generator.valueComponents.size()]);
+
+ public abstract Iterable<Row> batch(double ratio);
+ abstract void reset(double useChance, int targetCount);
+
+ public abstract boolean done();
+
+ public Partition partition()
+ {
+ return Partition.this;
+ }
+ }
+
+ // permits iterating a random subset of the procedurally generated rows in this partition; this is the only mechanism for visiting rows
+ // we maintain a stack of clustering components and their seeds; for each clustering component we visit, we generate all values it takes at that level,
+ // and then, using the average (total) number of children it takes we randomly choose whether or not we visit its children;
+ // if we do, we generate all possible values the children can take, and repeat the process. So at any one time we are using space proportional
+ // to C.N, where N is the average number of values each clustering component takes, as opposed to N^C total values in the partition.
+ class MultiRowIterator extends RowIterator
+ {
+
+ // probability any single row will be generated in this iteration
+ double useChance;
+ double expectedRowCount;
+
+ // the current seed in use at any given level; used to save recalculating it for each row, so we only need to recalc
+ // from prior row
+ final long[] clusteringSeeds = new long[generator.clusteringComponents.size()];
+ // the components remaining to be visited for each level of the current stack
+ final Queue<Object>[] clusteringComponents = new ArrayDeque[generator.clusteringComponents.size()];
+
+ // we want our chance of selection to be applied uniformly, so we compound the roll we make at each level
+ // so that we know with what chance we reached there, and we adjust our roll at that level by that amount
+ double[] chancemodifier = new double[generator.clusteringComponents.size()];
+ double[] rollmodifier = new double[generator.clusteringComponents.size()];
+
+ // reusable set for generating unique clustering components
+ final Set<Object> unique = new HashSet<>();
+ final Random random = new Random();
+
+ MultiRowIterator()
+ {
+ for (int i = 0 ; i < clusteringComponents.length ; i++)
+ clusteringComponents[i] = new ArrayDeque<>();
+ rollmodifier[0] = 1f;
+ chancemodifier[0] = generator.clusteringChildAverages[0];
+ }
+
+ void reset(double useChance, int targetCount)
+ {
+ generator.clusteringComponents.get(0).setSeed(idseed);
+ int firstComponentCount = (int) generator.clusteringComponents.get(0).clusteringDistribution.next();
+ this.expectedRowCount = firstComponentCount * generator.clusteringChildAverages[0];
+ if (Double.isNaN(useChance))
+ useChance = Math.max(0d, Math.min(1d, targetCount / expectedRowCount));
+
+ for (Queue<?> q : clusteringComponents)
+ q.clear();
+
+ this.useChance = useChance;
+ clusteringSeeds[0] = idseed;
+ clusteringComponents[0].add(this);
+ fill(clusteringComponents[0], firstComponentCount, generator.clusteringComponents.get(0));
+ advance(0, 1f);
+ }
+
+ void fill(int component)
+ {
+ long seed = clusteringSeeds[component - 1];
+ Generator gen = generator.clusteringComponents.get(component);
+ gen.setSeed(seed);
+ clusteringSeeds[component] = seed(clusteringComponents[component - 1].peek(), generator.clusteringComponents.get(component - 1).type, seed);
+ fill(clusteringComponents[component], (int) gen.clusteringDistribution.next(), gen);
+ }
+
+ void fill(Queue<Object> queue, int count, Generator generator)
+ {
+ if (count == 1)
+ {
+ queue.add(generator.generate());
+ }
+ else
+ {
+ unique.clear();
+ for (int i = 0 ; i < count ; i++)
+ {
+ Object next = generator.generate();
+ if (unique.add(next))
+ queue.add(next);
+ }
+ }
+ }
+
+ private boolean advance(double continueChance)
+ {
+ // we always start at the leaf level
+ int depth = clusteringComponents.length - 1;
+ // fill the row with the position we *were* at (unless pre-start)
+ for (int i = clusteringSeeds.length ; i < row.row.length ; i++)
+ {
+ Generator gen = generator.valueComponents.get(i - clusteringSeeds.length);
+ long seed = clusteringSeeds[depth];
+ seed = seed(clusteringComponents[depth].peek(), generator.clusteringComponents.get(depth).type, seed);
+ gen.setSeed(seed);
+ row.row[i] = gen.generate();
+ }
+ clusteringComponents[depth].poll();
+
+ return advance(depth, continueChance);
+ }
+
+ private boolean advance(int depth, double continueChance)
+ {
+ // advance the leaf component
+ clusteringComponents[depth].poll();
+ while (true)
+ {
+ if (clusteringComponents[depth].isEmpty())
+ {
+ if (depth == 0)
+ return false;
+ depth--;
+ clusteringComponents[depth].poll();
+ continue;
+ }
+
+ // the chance of descending is the uniform use chance, multiplied by the number of children
+ // we would on average generate (so if we have a 0.1 use chance, but should generate 10 children
+ // then we will always descend), multiplied by 1/(compound roll), where (compound roll) is the
+ // chance with which we reached this depth, i.e. if we already beat 50/50 odds, we double our
+ // chance of beating this next roll
+ double thischance = useChance * chancemodifier[depth];
+ if (thischance > 0.999f || thischance >= random.nextDouble())
+ {
+ row.row[depth] = clusteringComponents[depth].peek();
+ depth++;
+ if (depth == clusteringComponents.length)
+ break;
+ rollmodifier[depth] = rollmodifier[depth - 1] / Math.min(1d, thischance);
+ chancemodifier[depth] = generator.clusteringChildAverages[depth] * rollmodifier[depth];
+ fill(depth);
+ continue;
+ }
+
+ clusteringComponents[depth].poll();
+ }
+
+ return continueChance >= 1.0d || continueChance >= random.nextDouble();
+ }
+
+ public Iterable<Row> batch(final double ratio)
+ {
+ final double continueChance = 1d - (Math.pow(ratio, expectedRowCount * useChance));
+ return new Iterable<Row>()
+ {
+ public Iterator<Row> iterator()
+ {
+ return new Iterator<Row>()
+ {
+ boolean hasNext = true;
+ public boolean hasNext()
+ {
+ return hasNext;
+ }
+
+ public Row next()
+ {
+ hasNext = advance(continueChance);
+ return row;
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ }
+
+ public boolean done()
+ {
+ return clusteringComponents[0].isEmpty();
+ }
+
+ public Partition partition()
+ {
+ return Partition.this;
+ }
+ }
+
+ public String getKeyAsString()
+ {
+ StringBuilder sb = new StringBuilder();
+ int i = 0;
+ for (Object key : partitionKey)
+ {
+ if (i > 0)
+ sb.append("|");
+ AbstractType type = generator.partitionKey.get(i++).type;
+ sb.append(type.getString(type.decompose(key)));
+ }
+ return sb.toString();
+ }
+
+ static long seed(Object object, AbstractType type, long seed)
+ {
+ if (object instanceof ByteBuffer)
+ {
+ ByteBuffer buf = (ByteBuffer) object;
+ for (int i = buf.position() ; i < buf.limit() ; i++)
+ seed = (31 * seed) + buf.get(i);
+ return seed;
+ }
+ else if (object instanceof String)
+ {
+ String str = (String) object;
+ for (int i = 0 ; i < str.length() ; i++)
+ seed = (31 * seed) + str.charAt(i);
+ return seed;
+ }
+ else if (object instanceof Number)
+ {
+ return (seed * 31) + ((Number) object).longValue();
+ }
+ else if (object instanceof UUID)
+ {
+ return seed * 31 + (((UUID) object).getLeastSignificantBits() ^ ((UUID) object).getMostSignificantBits());
+ }
+ else
+ {
+ return seed(type.decompose(object), BytesType.instance, seed);
+ }
+ }
+
+ public Object getPartitionKey(int i)
+ {
+ return partitionKey[i];
+ }
+
+ // used for thrift smart routing - if it's a multi-part key we don't try to route correctly right now
+ public ByteBuffer getToken()
+ {
+ return generator.partitionKey.get(0).type.decompose(partitionKey[0]);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/PartitionGenerator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/PartitionGenerator.java b/tools/stress/src/org/apache/cassandra/stress/generate/PartitionGenerator.java
new file mode 100644
index 0000000..78002fb
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/PartitionGenerator.java
@@ -0,0 +1,80 @@
+package org.apache.cassandra.stress.generate;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import com.google.common.collect.Iterables;
+
+import org.apache.cassandra.stress.generate.values.Generator;
+
+public class PartitionGenerator
+{
+
+ public final double maxRowCount;
+ final List<Generator> partitionKey;
+ final List<Generator> clusteringComponents;
+ final List<Generator> valueComponents;
+ final int[] clusteringChildAverages;
+
+ private final Map<String, Integer> indexMap;
+
+ final List<Partition> recyclable = new ArrayList<>();
+ int partitionsInUse = 0;
+
+ public void reset()
+ {
+ partitionsInUse = 0;
+ }
+
+ public PartitionGenerator(List<Generator> partitionKey, List<Generator> clusteringComponents, List<Generator> valueComponents)
+ {
+ this.partitionKey = partitionKey;
+ this.clusteringComponents = clusteringComponents;
+ this.valueComponents = valueComponents;
+ this.clusteringChildAverages = new int[clusteringComponents.size()];
+ for (int i = clusteringChildAverages.length - 1 ; i >= 0 ; i--)
+ clusteringChildAverages[i] = (int) (i < (clusteringChildAverages.length - 1) ? clusteringComponents.get(i + 1).clusteringDistribution.average() * clusteringChildAverages[i + 1] : 1);
+ double maxRowCount = 1d;
+ for (Generator component : clusteringComponents)
+ maxRowCount *= component.clusteringDistribution.maxValue();
+ this.maxRowCount = maxRowCount;
+ this.indexMap = new HashMap<>();
+ int i = 0;
+ for (Generator generator : partitionKey)
+ indexMap.put(generator.name, --i);
+ i = 0;
+ for (Generator generator : Iterables.concat(clusteringComponents, valueComponents))
+ indexMap.put(generator.name, i++);
+ }
+
+ public int indexOf(String name)
+ {
+ Integer i = indexMap.get(name);
+ if (i == null)
+ throw new NoSuchElementException();
+ return i;
+ }
+
+ public Partition generate(long seed)
+ {
+ if (recyclable.size() <= partitionsInUse || recyclable.get(partitionsInUse) == null)
+ recyclable.add(new Partition(this));
+
+ Partition partition = recyclable.get(partitionsInUse++);
+ partition.setSeed(seed);
+ return partition;
+ }
+
+ public ByteBuffer convert(int c, Object v)
+ {
+ if (c < 0)
+ return partitionKey.get(-1-c).type.decompose(v);
+ if (c < clusteringComponents.size())
+ return clusteringComponents.get(c).type.decompose(v);
+ return valueComponents.get(c - clusteringComponents.size()).type.decompose(v);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistribution.java b/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistribution.java
new file mode 100644
index 0000000..fb5a373
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistribution.java
@@ -0,0 +1,25 @@
+package org.apache.cassandra.stress.generate;
+
+public class RatioDistribution
+{
+
+ final Distribution distribution;
+ final double divisor;
+
+ public RatioDistribution(Distribution distribution, double divisor)
+ {
+ this.distribution = distribution;
+ this.divisor = divisor;
+ }
+
+ // yields a value between 0 and 1
+ public double next()
+ {
+ return Math.max(0f, Math.min(1f, distribution.nextDouble() / divisor));
+ }
+
+ public double max()
+ {
+ return Math.min(1d, distribution.maxValue() / divisor);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistributionFactory.java
new file mode 100644
index 0000000..16474d8
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistributionFactory.java
@@ -0,0 +1,31 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.Serializable;
+
+public interface RatioDistributionFactory extends Serializable
+{
+
+ RatioDistribution get();
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/Row.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/Row.java b/tools/stress/src/org/apache/cassandra/stress/generate/Row.java
new file mode 100644
index 0000000..d3b9a2a
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/Row.java
@@ -0,0 +1,22 @@
+package org.apache.cassandra.stress.generate;
+
+public class Row
+{
+
+ final Object[] partitionKey;
+ final Object[] row;
+
+ public Row(Object[] partitionKey, Object[] row)
+ {
+ this.partitionKey = partitionKey;
+ this.row = row;
+ }
+
+ public Object get(int column)
+ {
+ if (column < 0)
+ return partitionKey[-1-column];
+ return row[column];
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/SeedGenerator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/SeedGenerator.java b/tools/stress/src/org/apache/cassandra/stress/generate/SeedGenerator.java
new file mode 100644
index 0000000..6c1bc7f
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/SeedGenerator.java
@@ -0,0 +1,8 @@
+package org.apache.cassandra.stress.generate;
+
+public interface SeedGenerator
+{
+
+ long next(long workIndex);
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/SeedRandomGenerator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/SeedRandomGenerator.java b/tools/stress/src/org/apache/cassandra/stress/generate/SeedRandomGenerator.java
new file mode 100644
index 0000000..bbaaeb8
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/SeedRandomGenerator.java
@@ -0,0 +1,33 @@
+package org.apache.cassandra.stress.generate;
+
+public class SeedRandomGenerator implements SeedGenerator
+{
+
+ final Distribution distribution;
+ final Distribution clustering;
+
+ private long next;
+ private int count;
+
+ public SeedRandomGenerator(Distribution distribution, Distribution clustering)
+ {
+ this.distribution = distribution;
+ this.clustering = clustering;
+ }
+
+ public long next(long workIndex)
+ {
+ if (count == 0)
+ {
+ next = distribution.next();
+ count = (int) clustering.next();
+ }
+ long result = next;
+ count--;
+ if (next == distribution.maxValue())
+ next = distribution.minValue();
+ else
+ next++;
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/SeedSeriesGenerator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/SeedSeriesGenerator.java b/tools/stress/src/org/apache/cassandra/stress/generate/SeedSeriesGenerator.java
new file mode 100644
index 0000000..27967d2
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/SeedSeriesGenerator.java
@@ -0,0 +1,21 @@
+package org.apache.cassandra.stress.generate;
+
+public class SeedSeriesGenerator implements SeedGenerator
+{
+
+ final long min;
+ final long count;
+
+ public SeedSeriesGenerator(long min, long max)
+ {
+ if (min > max)
+ throw new IllegalStateException();
+ this.min = min;
+ this.count = 1 + max - min;
+ }
+
+ public long next(long workIndex)
+ {
+ return min + (workIndex % count);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Booleans.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Booleans.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Booleans.java
new file mode 100644
index 0000000..b1d84d6
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Booleans.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.BooleanType;
+
+public class Booleans extends Generator<Boolean>
+{
+ public Booleans(String name, GeneratorConfig config)
+ {
+ super(BooleanType.instance, config, name);
+ }
+
+ @Override
+ public Boolean generate()
+ {
+ return identityDistribution.next() % 1 == 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Bytes.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Bytes.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Bytes.java
new file mode 100644
index 0000000..2a5bddf
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Bytes.java
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.BytesType;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
+
+public class Bytes extends Generator<ByteBuffer>
+{
+ private final byte[] bytes;
+ private final Random rand = new Random();
+
+ public Bytes(String name, GeneratorConfig config)
+ {
+ super(BytesType.instance, config, name);
+ bytes = new byte[(int) sizeDistribution.maxValue()];
+ }
+
+ @Override
+ public ByteBuffer generate()
+ {
+ long seed = identityDistribution.next();
+ sizeDistribution.setSeed(seed);
+ rand.setSeed(~seed);
+ int size = (int) sizeDistribution.next();
+ for (int i = 0; i < size; )
+ for (int v = rand.nextInt(),
+ n = Math.min(size - i, Integer.SIZE/Byte.SIZE);
+ n-- > 0; v >>= Byte.SIZE)
+ bytes[i++] = (byte)v;
+ return ByteBuffer.wrap(Arrays.copyOf(bytes, size));
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Dates.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Dates.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Dates.java
new file mode 100644
index 0000000..7d36be2
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Dates.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.util.Date;
+
+import org.apache.cassandra.db.marshal.DateType;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.settings.OptionDistribution;
+
+public class Dates extends Generator<Date>
+{
+ public Dates(String name, GeneratorConfig config)
+ {
+ super(DateType.instance, config, name);
+ }
+
+ @Override
+ public Date generate()
+ {
+ return new Date(identityDistribution.next());
+ }
+
+ DistributionFactory defaultIdentityDistribution()
+ {
+ return OptionDistribution.get("uniform(1.." + Long.toString(50L*365L*24L*60L*60L*1000L) + ")");
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Doubles.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Doubles.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Doubles.java
new file mode 100644
index 0000000..76e983d
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Doubles.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.DoubleType;
+
+public class Doubles extends Generator<Double>
+{
+ public Doubles(String name, GeneratorConfig config)
+ {
+ super(DoubleType.instance, config, name);
+ }
+
+ @Override
+ public Double generate()
+ {
+ return identityDistribution.nextDouble();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Floats.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Floats.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Floats.java
new file mode 100644
index 0000000..8e23c11
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Floats.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.FloatType;
+
+public class Floats extends Generator<Float>
+{
+ public Floats(String name, GeneratorConfig config)
+ {
+ super(FloatType.instance, config, name);
+ }
+
+ @Override
+ public Float generate()
+ {
+ return (float) identityDistribution.nextDouble();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Generator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Generator.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Generator.java
new file mode 100644
index 0000000..13343de
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Generator.java
@@ -0,0 +1,50 @@
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.settings.OptionDistribution;
+
+public abstract class Generator<T>
+{
+
+ public final String name;
+ public final AbstractType<T> type;
+ final long salt;
+ final Distribution identityDistribution;
+ final Distribution sizeDistribution;
+ public final Distribution clusteringDistribution;
+
+ public Generator(AbstractType<T> type, GeneratorConfig config, String name)
+ {
+ this.type = type;
+ this.name = name;
+ this.salt = config.salt;
+ this.identityDistribution = config.getIdentityDistribution(defaultIdentityDistribution());
+ this.sizeDistribution = config.getSizeDistribution(defaultSizeDistribution());
+ this.clusteringDistribution = config.getClusteringDistribution(defaultClusteringDistribution());
+ }
+
+ public void setSeed(long seed)
+ {
+ identityDistribution.setSeed(seed ^ salt);
+ clusteringDistribution.setSeed(seed ^ ~salt);
+ }
+
+ public abstract T generate();
+
+ DistributionFactory defaultIdentityDistribution()
+ {
+ return OptionDistribution.get("uniform(1..100B)");
+ }
+
+ DistributionFactory defaultSizeDistribution()
+ {
+ return OptionDistribution.get("uniform(4..8)");
+ }
+
+ DistributionFactory defaultClusteringDistribution()
+ {
+ return OptionDistribution.get("fixed(1)");
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/GeneratorConfig.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/GeneratorConfig.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/GeneratorConfig.java
new file mode 100644
index 0000000..8f7b2ea
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/GeneratorConfig.java
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.MurmurHash;
+
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.Map;
+
+public class GeneratorConfig implements Serializable
+{
+ public final long salt;
+
+ private final DistributionFactory clusteringDistributions;
+ private final DistributionFactory sizeDistributions;
+ private final DistributionFactory identityDistributions;
+
+ public GeneratorConfig(String seedStr, DistributionFactory clusteringDistributions, DistributionFactory sizeDistributions, DistributionFactory identityDistributions)
+ {
+ this.clusteringDistributions = clusteringDistributions;
+ this.sizeDistributions = sizeDistributions;
+ this.identityDistributions = identityDistributions;
+ ByteBuffer buf = ByteBufferUtil.bytes(seedStr);
+ long[] hash = new long[2];
+ MurmurHash.hash3_x64_128(buf, buf.position(), buf.remaining(), 0, hash);
+ salt = hash[0];
+ }
+
+ Distribution getClusteringDistribution(DistributionFactory deflt)
+ {
+ return (clusteringDistributions == null ? deflt : clusteringDistributions).get();
+ }
+
+ Distribution getIdentityDistribution(DistributionFactory deflt)
+ {
+ return (identityDistributions == null ? deflt : identityDistributions).get();
+ }
+
+ Distribution getSizeDistribution(DistributionFactory deflt)
+ {
+ return (sizeDistributions == null ? deflt : sizeDistributions).get();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/HexBytes.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/HexBytes.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/HexBytes.java
new file mode 100644
index 0000000..db46bac
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/HexBytes.java
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import org.apache.cassandra.db.marshal.BytesType;
+
+public class HexBytes extends Generator<ByteBuffer>
+{
+ private final byte[] bytes;
+
+ public HexBytes(String name, GeneratorConfig config)
+ {
+ super(BytesType.instance, config, name);
+ bytes = new byte[(int) sizeDistribution.maxValue()];
+ }
+
+ @Override
+ public ByteBuffer generate()
+ {
+ long seed = identityDistribution.next();
+ sizeDistribution.setSeed(seed);
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i +=16)
+ {
+ long value = identityDistribution.next();
+ for (int j = 0 ; j < 16 && i + j < size ; j++)
+ {
+ int v = (int) (value & 15);
+ bytes[i + j] = (byte) ((v < 10 ? '0' : 'A') + v);
+ value >>>= 4;
+ }
+ }
+ return ByteBuffer.wrap(Arrays.copyOf(bytes, size));
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/HexStrings.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/HexStrings.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/HexStrings.java
new file mode 100644
index 0000000..ce65b8a
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/HexStrings.java
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.util.Random;
+
+import org.apache.cassandra.db.marshal.UTF8Type;
+
+public class HexStrings extends Generator<String>
+{
+ private final char[] chars;
+
+ public HexStrings(String name, GeneratorConfig config)
+ {
+ super(UTF8Type.instance, config, name);
+ chars = new char[(int) sizeDistribution.maxValue()];
+ }
+
+ @Override
+ public String generate()
+ {
+ long seed = identityDistribution.next();
+ sizeDistribution.setSeed(seed);
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i +=16)
+ {
+ long value = identityDistribution.next();
+ for (int j = 0 ; j < 16 && i + j < size ; j++)
+ {
+ int v = (int) (value & 15);
+ chars[i + j] = (char) ((v < 10 ? '0' : 'A') + v);
+ value >>>= 4;
+ }
+ }
+ return new String(chars, 0, size);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Inets.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Inets.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Inets.java
new file mode 100644
index 0000000..334d73c
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Inets.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.apache.cassandra.db.marshal.InetAddressType;
+
+
+public class Inets extends Generator<InetAddress>
+{
+ final byte[] buf;
+ public Inets(String name, GeneratorConfig config)
+ {
+ super(InetAddressType.instance, config, name);
+ buf = new byte[4];
+ }
+
+ @Override
+ public InetAddress generate()
+ {
+ int val = (int) identityDistribution.next();
+
+ buf[0] = (byte)(val >>> 24);
+ buf[1] = (byte)(val >>> 16);
+ buf[2] = (byte)(val >>> 8);
+ buf[3] = (byte)val;
+
+ try
+ {
+ return InetAddress.getByAddress(buf);
+ }
+ catch (UnknownHostException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Integers.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Integers.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Integers.java
new file mode 100644
index 0000000..8b9b33a
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Integers.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.Int32Type;
+
+public class Integers extends Generator<Integer>
+{
+
+ public Integers(String name, GeneratorConfig config)
+ {
+ super(Int32Type.instance, config, name);
+ }
+
+ @Override
+ public Integer generate()
+ {
+ return (int) identityDistribution.next();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
new file mode 100644
index 0000000..d188f7e
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.cassandra.db.marshal.ListType;
+
+public class Lists extends Generator<List>
+{
+ final Generator valueType;
+ final Object[] buffer;
+
+ public Lists(String name, Generator valueType, GeneratorConfig config)
+ {
+ super(ListType.getInstance(valueType.type), config, name);
+ this.valueType = valueType;
+ buffer = new Object[(int) sizeDistribution.maxValue()];
+ }
+
+ public void setSeed(long seed)
+ {
+ super.setSeed(seed);
+ valueType.setSeed(seed * 31);
+ }
+
+ @Override
+ public List generate()
+ {
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i++)
+ buffer[i] = valueType.generate();
+ return com.google.common.collect.Lists.newArrayList(Arrays.copyOf(buffer, size));
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Longs.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Longs.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Longs.java
new file mode 100644
index 0000000..0584ed1
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Longs.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.LongType;
+
+public class Longs extends Generator<Long>
+{
+ public Longs(String name, GeneratorConfig config)
+ {
+ super(LongType.instance, config, name);
+ }
+
+ @Override
+ public Long generate()
+ {
+ return identityDistribution.next();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
new file mode 100644
index 0000000..48bf293
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.cassandra.db.marshal.SetType;
+
+public class Sets extends Generator<Set>
+{
+ final Generator valueType;
+
+ public Sets(String name, Generator valueType, GeneratorConfig config)
+ {
+ super(SetType.getInstance(valueType.type), config, name);
+ this.valueType = valueType;
+ }
+
+ public void setSeed(long seed)
+ {
+ super.setSeed(seed);
+ valueType.setSeed(seed * 31);
+ }
+
+ @Override
+ public Set generate()
+ {
+ final Set set = new HashSet();
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i++)
+ set.add(valueType.generate());
+ return set;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Strings.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Strings.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Strings.java
new file mode 100644
index 0000000..e01ff20
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Strings.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.util.Random;
+
+import org.apache.cassandra.db.marshal.UTF8Type;
+
+public class Strings extends Generator<String>
+{
+ private final char[] chars;
+ private final Random rnd = new Random();
+
+ public Strings(String name, GeneratorConfig config)
+ {
+ super(UTF8Type.instance, config, name);
+ chars = new char[(int) sizeDistribution.maxValue()];
+ }
+
+ @Override
+ public String generate()
+ {
+ long seed = identityDistribution.next();
+ sizeDistribution.setSeed(seed);
+ rnd.setSeed(~seed);
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i++)
+ chars[i] = (char) (32 +rnd.nextInt(128-32));
+ return new String(chars, 0, size);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java
new file mode 100644
index 0000000..714959d
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+
+import org.apache.cassandra.db.marshal.TimeUUIDType;
+import org.apache.cassandra.utils.UUIDGen;
+
+import java.util.UUID;
+
+public class TimeUUIDs extends Generator<UUID>
+{
+ final Dates dateGen;
+ final long clockSeqAndNode;
+
+ public TimeUUIDs(String name, GeneratorConfig config)
+ {
+ super(TimeUUIDType.instance, config, name);
+ dateGen = new Dates(name, config);
+ clockSeqAndNode = config.salt;
+ }
+
+ public void setSeed(long seed)
+ {
+ dateGen.setSeed(seed);
+ }
+
+ @Override
+ public UUID generate()
+ {
+ return UUIDGen.getTimeUUID(dateGen.generate().getTime(), clockSeqAndNode);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/UUIDs.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/UUIDs.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/UUIDs.java
new file mode 100644
index 0000000..e8d6501
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/UUIDs.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.util.UUID;
+
+import org.apache.cassandra.db.marshal.UUIDType;
+
+public class UUIDs extends Generator<UUID>
+{
+ public UUIDs(String name, GeneratorConfig config)
+ {
+ super(UUIDType.instance, config, name);
+ }
+
+ @Override
+ public UUID generate()
+ {
+ return new UUID(identityDistribution.next(), identityDistribution.next());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGen.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGen.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGen.java
deleted file mode 100644
index 334506d..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGen.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.List;
-
-public abstract class DataGen
-{
-
- public abstract void generate(ByteBuffer fill, long index, ByteBuffer seed);
- public abstract boolean isDeterministic();
-
- public void generate(List<ByteBuffer> fills, long index, ByteBuffer seed)
- {
- for (ByteBuffer fill : fills)
- generate(fill, index++, seed);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenBytesRandom.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenBytesRandom.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenBytesRandom.java
deleted file mode 100644
index 1dc77b4..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenBytesRandom.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.Random;
-
-public class DataGenBytesRandom extends DataGen
-{
-
- private final Random rnd = new Random();
-
- @Override
- public void generate(ByteBuffer fill, long index, ByteBuffer seed)
- {
- fill.clear();
- rnd.nextBytes(fill.array());
- }
-
- @Override
- public boolean isDeterministic()
- {
- return false;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenFactory.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenFactory.java
deleted file mode 100644
index dadb792..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenFactory.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.Serializable;
-
-public interface DataGenFactory extends Serializable
-{
- DataGen get();
-}
-
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHex.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHex.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHex.java
deleted file mode 100644
index 124a07b..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHex.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-
-public abstract class DataGenHex extends DataGen
-{
-
- abstract long next(long operationIndex);
-
- @Override
- public final void generate(ByteBuffer fill, long operationIndex, ByteBuffer seed)
- {
- fill.clear();
- fillKeyStringBytes(next(operationIndex), fill.array());
- }
-
- public static void fillKeyStringBytes(long key, byte[] fill)
- {
- int ub = fill.length - 1;
- int offset = 0;
- while (key != 0)
- {
- int digit = ((int) key) & 15;
- key >>>= 4;
- fill[ub - offset++] = digit(digit);
- }
- while (offset < fill.length)
- fill[ub - offset++] = '0';
- }
-
- // needs to be UTF-8, but for these chars there is no difference
- private static byte digit(int num)
- {
- if (num < 10)
- return (byte)('0' + num);
- return (byte)('A' + (num - 10));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromDistribution.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromDistribution.java
deleted file mode 100644
index 25284dc..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromDistribution.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import org.apache.commons.math3.distribution.NormalDistribution;
-import org.apache.commons.math3.distribution.UniformRealDistribution;
-
-public class DataGenHexFromDistribution extends DataGenHex
-{
-
- final Distribution distribution;
-
- public DataGenHexFromDistribution(Distribution distribution)
- {
- this.distribution = distribution;
- }
-
- @Override
- public boolean isDeterministic()
- {
- return false;
- }
-
- @Override
- long next(long operationIndex)
- {
- return distribution.next();
- }
-
- public static DataGenHex buildGaussian(long minKey, long maxKey, double stdevsToLimit)
- {
- double midRange = (maxKey + minKey) / 2d;
- double halfRange = (maxKey - minKey) / 2d;
- return new DataGenHexFromDistribution(new DistributionBoundApache(new NormalDistribution(midRange, halfRange / stdevsToLimit), minKey, maxKey));
- }
-
- public static DataGenHex buildGaussian(long minKey, long maxKey, double mean, double stdev)
- {
- return new DataGenHexFromDistribution(new DistributionBoundApache(new NormalDistribution(mean, stdev), minKey, maxKey));
- }
-
- public static DataGenHex buildUniform(long minKey, long maxKey)
- {
- return new DataGenHexFromDistribution(new DistributionBoundApache(new UniformRealDistribution(minKey, maxKey), minKey, maxKey));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromOpIndex.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromOpIndex.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromOpIndex.java
deleted file mode 100644
index e6bda68..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromOpIndex.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-public class DataGenHexFromOpIndex extends DataGenHex
-{
-
- final long minKey;
- final long maxKey;
-
- public DataGenHexFromOpIndex(long minKey, long maxKey)
- {
- this.minKey = minKey;
- this.maxKey = maxKey;
- }
-
- @Override
- public boolean isDeterministic()
- {
- return true;
- }
-
- @Override
- long next(long operationIndex)
- {
- long range = maxKey + 1 - minKey;
- return Math.abs((operationIndex % range) + minKey);
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringDictionary.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringDictionary.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringDictionary.java
deleted file mode 100644
index 73814cb..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringDictionary.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.math3.distribution.EnumeratedDistribution;
-import org.apache.commons.math3.util.Pair;
-
-import static com.google.common.base.Charsets.UTF_8;
-
-public class DataGenStringDictionary extends DataGen
-{
-
- private final byte space = ' ';
- private final EnumeratedDistribution<byte[]> words;
-
- public DataGenStringDictionary(EnumeratedDistribution<byte[]> wordDistribution)
- {
- words = wordDistribution;
- }
-
- @Override
- public void generate(ByteBuffer fill, long index, ByteBuffer seed)
- {
- fill(fill);
- }
-
- @Override
- public void generate(List<ByteBuffer> fills, long index, ByteBuffer seed)
- {
- for (int i = 0 ; i < fills.size() ; i++)
- fill(fills.get(0));
- }
-
- private void fill(ByteBuffer fill)
- {
- fill.clear();
- byte[] trg = fill.array();
- int i = 0;
- while (i < trg.length)
- {
- if (i > 0)
- trg[i++] = space;
- byte[] src = words.sample();
- System.arraycopy(src, 0, trg, i, Math.min(src.length, trg.length - i));
- i += src.length;
- }
- }
-
- @Override
- public boolean isDeterministic()
- {
- return false;
- }
-
- public static DataGenFactory getFactory(File file) throws IOException
- {
- final List<Pair<byte[], Double>> words = new ArrayList<>();
- try (final BufferedReader reader = new BufferedReader(new FileReader(file)))
- {
- String line;
- while ( null != (line = reader.readLine()) )
- {
- String[] pair = line.split(" +");
- if (pair.length != 2)
- throw new IllegalArgumentException("Invalid record in dictionary: \"" + line + "\"");
- words.add(new Pair<>(pair[1].getBytes(UTF_8), Double.parseDouble(pair[0])));
- }
- final EnumeratedDistribution<byte[]> dist = new EnumeratedDistribution<byte[]>(words);
- return new DataGenFactory()
- {
- @Override
- public DataGen get()
- {
- return new DataGenStringDictionary(dist);
- }
- };
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringRepeats.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringRepeats.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringRepeats.java
deleted file mode 100644
index ad7cb24..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringRepeats.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.security.MessageDigest;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.cassandra.utils.FBUtilities;
-
-import static com.google.common.base.Charsets.UTF_8;
-
-public class DataGenStringRepeats extends DataGen
-{
-
- private static final ConcurrentHashMap<Integer, ConcurrentHashMap<Long, byte[]>> CACHE_LOOKUP = new ConcurrentHashMap<>();
-
- private final ConcurrentHashMap<Long, byte[]> cache;
- private final int repeatFrequency;
- public DataGenStringRepeats(int repeatFrequency)
- {
- if (!CACHE_LOOKUP.containsKey(repeatFrequency))
- CACHE_LOOKUP.putIfAbsent(repeatFrequency, new ConcurrentHashMap<Long, byte[]>());
- cache = CACHE_LOOKUP.get(repeatFrequency);
- this.repeatFrequency = repeatFrequency;
- }
-
- @Override
- public void generate(ByteBuffer fill, long index, ByteBuffer seed)
- {
- fill(fill, index, 0, seed);
- }
-
- @Override
- public void generate(List<ByteBuffer> fills, long index, ByteBuffer seed)
- {
- for (int i = 0 ; i < fills.size() ; i++)
- {
- fill(fills.get(i), index, i, seed);
- }
- }
-
- private void fill(ByteBuffer fill, long index, int column, ByteBuffer seed)
- {
- fill.clear();
- byte[] trg = fill.array();
- byte[] src = getData(index, column, seed);
- for (int j = 0 ; j < trg.length ; j += src.length)
- System.arraycopy(src, 0, trg, j, Math.min(src.length, trg.length - j));
- }
-
- private byte[] getData(long index, int column, ByteBuffer seed)
- {
- final long key = ((long)column * repeatFrequency) + ((seed == null ? index : Math.abs(seed.hashCode())) % repeatFrequency);
- byte[] r = cache.get(key);
- if (r != null)
- return r;
- MessageDigest md = FBUtilities.threadLocalMD5Digest();
- r = md.digest(Long.toString(key).getBytes(UTF_8));
- cache.putIfAbsent(key, r);
- return r;
- }
-
- @Override
- public boolean isDeterministic()
- {
- return true;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/Distribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/Distribution.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/Distribution.java
deleted file mode 100644
index ed40290..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/Distribution.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-public abstract class Distribution
-{
-
- public abstract long next();
- public abstract long inverseCumProb(double cumProb);
-
- public long maxValue()
- {
- return inverseCumProb(1d);
- }
-
- public long minValue()
- {
- return inverseCumProb(0d);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionBoundApache.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionBoundApache.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionBoundApache.java
deleted file mode 100644
index 0fdd437..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionBoundApache.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import org.apache.commons.math3.distribution.AbstractRealDistribution;
-
-public class DistributionBoundApache extends Distribution
-{
-
- final AbstractRealDistribution delegate;
- final long min, max;
-
- public DistributionBoundApache(AbstractRealDistribution delegate, long min, long max)
- {
- this.delegate = delegate;
- this.min = min;
- this.max = max;
- }
-
- @Override
- public long next()
- {
- return bound(min, max, delegate.sample());
- }
-
- @Override
- public long inverseCumProb(double cumProb)
- {
- return bound(min, max, delegate.inverseCumulativeProbability(cumProb));
- }
-
- private static long bound(long min, long max, double val)
- {
- long r = (long) val;
- if ((r >= min) & (r <= max))
- return r;
- if (r < min)
- return min;
- if (r > max)
- return max;
- throw new IllegalStateException();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFactory.java
deleted file mode 100644
index b80f851..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFactory.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.Serializable;
-
-public interface DistributionFactory extends Serializable
-{
-
- Distribution get();
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFixed.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFixed.java
deleted file mode 100644
index 43372ca..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFixed.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-public class DistributionFixed extends Distribution
-{
-
- final long key;
-
- public DistributionFixed(long key)
- {
- this.key = key;
- }
-
- @Override
- public long next()
- {
- return key;
- }
-
- @Override
- public long inverseCumProb(double cumProb)
- {
- return key;
- }
-
-}
[17/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java
deleted file mode 100644
index 021c4e8..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.util.ThriftClient;
-import org.apache.cassandra.thrift.ColumnParent;
-import org.apache.cassandra.thrift.KeyRange;
-import org.apache.cassandra.thrift.SlicePredicate;
-import org.apache.cassandra.thrift.SliceRange;
-import org.apache.cassandra.utils.ByteBufferUtil;
-
-public final class ThriftRangeSlicer extends Operation
-{
-
- public ThriftRangeSlicer(State state, long index)
- {
- super(state, index);
- }
-
- @Override
- public void run(final ThriftClient client) throws IOException
- {
- final SlicePredicate predicate = new SlicePredicate()
- .setSlice_range(
- new SliceRange(
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- false,
- state.settings.columns.maxColumnsPerKey
- )
- );
-
- final ByteBuffer start = getKey();
- final KeyRange range =
- new KeyRange(state.settings.columns.maxColumnsPerKey)
- .setStart_key(start)
- .setEnd_key(ByteBufferUtil.EMPTY_BYTE_BUFFER)
- .setCount(state.settings.command.keysAtOnce);
-
- for (final ColumnParent parent : state.columnParents)
- {
- timeWithRetry(new RunOp()
- {
- private int count = 0;
- @Override
- public boolean run() throws Exception
- {
- return (count = client.get_range_slices(parent, predicate, range, state.settings.command.consistencyLevel).size()) != 0;
- }
-
- @Override
- public String key()
- {
- return new String(range.bufferForStart_key().array());
- }
-
- @Override
- public int keyCount()
- {
- return count;
- }
- });
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java
deleted file mode 100644
index dccf469..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.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;
-import org.apache.cassandra.thrift.ColumnOrSuperColumn;
-import org.apache.cassandra.thrift.ColumnParent;
-import org.apache.cassandra.thrift.SlicePredicate;
-import org.apache.cassandra.thrift.SuperColumn;
-
-public final class ThriftReader extends Operation
-{
-
- public ThriftReader(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
- final SlicePredicate predicate = slicePredicate();
- final ByteBuffer key = getKey();
- final List<ByteBuffer> expect = state.rowGen.isDeterministic() ? generateColumnValues(key) : null;
- for (final ColumnParent parent : state.columnParents)
- {
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- List<ColumnOrSuperColumn> 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())
- return false;
- for (int i = 0 ; i < row.size() ; i++)
- if (!row.get(i).getColumn().bufferForValue().equals(expect.get(i)))
- return false;
- }
- else
- {
- for (ColumnOrSuperColumn col : row)
- {
- SuperColumn superColumn = col.getSuper_column();
- if (superColumn.getColumns().size() != expect.size())
- return false;
- for (int i = 0 ; i < expect.size() ; i++)
- if (!superColumn.getColumns().get(i).bufferForValue().equals(expect.get(i)))
- return false;
- }
- }
- return true;
- }
-
- @Override
- public String key()
- {
- return new String(key.array());
- }
-
- @Override
- public int keyCount()
- {
- return 1;
- }
- });
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
new file mode 100644
index 0000000..f794e75
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
@@ -0,0 +1,84 @@
+package org.apache.cassandra.stress.operations.predefined;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+
+public class CqlCounterAdder extends CqlOperation<Integer>
+{
+
+ final Distribution counteradd;
+ public CqlCounterAdder(DistributionFactory counteradd, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_WRITE, timer, generator, settings);
+ this.counteradd = counteradd.get();
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ String counterCF = isCql2() ? type.table : "Counter3";
+
+ StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(counterCF));
+
+ if (isCql2())
+ query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
+
+ query.append(" SET ");
+
+ // TODO : increment distribution subset of columns
+ for (int i = 0; i < settings.columns.maxColumnsPerKey; i++)
+ {
+ if (i > 0)
+ query.append(",");
+
+ query.append('C').append(i).append("=C").append(i).append("+?");
+ }
+ query.append(" WHERE KEY=?");
+ return query.toString();
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ final List<Object> list = new ArrayList<>();
+ for (int i = 0; i < settings.columns.maxColumnsPerKey; i++)
+ list.add(counteradd.next());
+ list.add(ByteBuffer.wrap(key));
+ return list;
+ }
+
+ @Override
+ protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ return new CqlRunOpAlwaysSucceed(client, query, queryId, params, key, 1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
new file mode 100644
index 0000000..94c8faf
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
@@ -0,0 +1,74 @@
+package org.apache.cassandra.stress.operations.predefined;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+
+public class CqlCounterGetter extends CqlOperation<Integer>
+{
+
+ public CqlCounterGetter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_READ, timer, generator, settings);
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ return Collections.<Object>singletonList(ByteBuffer.wrap(key));
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ StringBuilder query = new StringBuilder("SELECT ");
+
+ // TODO: obey slice/noslice option (instead of always slicing)
+ if (isCql2())
+ query.append("FIRST ").append(settings.columns.maxColumnsPerKey).append(" ''..''");
+ else
+ query.append("*");
+
+ String counterCF = isCql2() ? type.table : "Counter3";
+
+ query.append(" FROM ").append(wrapInQuotesIfRequired(counterCF));
+
+ if (isCql2())
+ query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
+
+ return query.append(" WHERE KEY=?").toString();
+ }
+
+ @Override
+ protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ return new CqlRunOpTestNonEmpty(client, query, queryId, params, key);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
new file mode 100644
index 0000000..c422f2b
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
@@ -0,0 +1,79 @@
+package org.apache.cassandra.stress.operations.predefined;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.utils.UUIDGen;
+
+public class CqlInserter extends CqlOperation<Integer>
+{
+
+ public CqlInserter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.WRITE, timer, generator, settings);
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(type.table));
+
+ if (isCql2())
+ query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
+
+ query.append(" SET ");
+
+ for (int i = 0 ; i < settings.columns.maxColumnsPerKey ; i++)
+ {
+ if (i > 0)
+ query.append(',');
+
+ query.append(wrapInQuotesIfRequired(settings.columns.namestrs.get(i))).append(" = ?");
+ }
+
+ query.append(" WHERE KEY=?");
+ return query.toString();
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ final ArrayList<Object> queryParams = new ArrayList<>();
+ List<ByteBuffer> values = getColumnValues();
+ queryParams.addAll(values);
+ queryParams.add(ByteBuffer.wrap(key));
+ return queryParams;
+ }
+
+ @Override
+ protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ return new CqlRunOpAlwaysSucceed(client, query, queryId, params, key, 1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
new file mode 100644
index 0000000..0264cd1
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
@@ -0,0 +1,714 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.google.common.base.Function;
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.StressMetrics;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.ConnectionStyle;
+import org.apache.cassandra.stress.settings.CqlVersion;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.Compression;
+import org.apache.cassandra.thrift.CqlResult;
+import org.apache.cassandra.thrift.CqlRow;
+import org.apache.cassandra.thrift.ThriftConversion;
+import org.apache.cassandra.transport.SimpleClient;
+import org.apache.cassandra.transport.messages.ResultMessage;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.thrift.TException;
+
+public abstract class CqlOperation<V> extends PredefinedOperation
+{
+
+ protected abstract List<Object> getQueryParameters(byte[] key);
+ protected abstract String buildQuery();
+ protected abstract CqlRunOp<V> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key);
+
+ public CqlOperation(Command type, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(type, timer, generator, settings);
+ if (settings.columns.variableColumnCount)
+ throw new IllegalStateException("Variable column counts are not implemented for CQL");
+ }
+
+ protected CqlRunOp<V> run(final ClientWrapper client, final List<Object> queryParams, final ByteBuffer key) throws IOException
+ {
+ final CqlRunOp<V> op;
+ if (settings.mode.style == ConnectionStyle.CQL_PREPARED)
+ {
+ final Object id;
+ Object idobj = getCqlCache();
+ if (idobj == null)
+ {
+ try
+ {
+ id = client.createPreparedStatement(buildQuery());
+ } catch (TException e)
+ {
+ throw new RuntimeException(e);
+ }
+ storeCqlCache(id);
+ }
+ else
+ id = idobj;
+
+ op = buildRunOp(client, null, id, queryParams, key);
+ }
+ else
+ {
+ final String query;
+ Object qobj = getCqlCache();
+ if (qobj == null)
+ storeCqlCache(query = buildQuery());
+ else
+ query = qobj.toString();
+
+ op = buildRunOp(client, query, null, queryParams, key);
+ }
+
+ timeWithRetry(op);
+ return op;
+ }
+
+ protected void run(final ClientWrapper client) throws IOException
+ {
+ final byte[] key = getKey().array();
+ final List<Object> queryParams = getQueryParameters(key);
+ run(client, queryParams, ByteBuffer.wrap(key));
+ }
+
+ // Classes to process Cql results
+
+ // Always succeeds so long as the query executes without error; provides a keyCount to increment on instantiation
+ protected final class CqlRunOpAlwaysSucceed extends CqlRunOp<Integer>
+ {
+
+ final int keyCount;
+
+ protected CqlRunOpAlwaysSucceed(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key, int keyCount)
+ {
+ super(client, query, queryId, RowCountHandler.INSTANCE, params, key);
+ this.keyCount = keyCount;
+ }
+
+ @Override
+ public boolean validate(Integer result)
+ {
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return keyCount;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return keyCount;
+ }
+ }
+
+ // Succeeds so long as the result set is nonempty, and the query executes without error
+ protected final class CqlRunOpTestNonEmpty extends CqlRunOp<Integer>
+ {
+
+ protected CqlRunOpTestNonEmpty(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ super(client, query, queryId, RowCountHandler.INSTANCE, params, key);
+ }
+
+ @Override
+ public boolean validate(Integer result)
+ {
+ return result > 0;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return result;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return result;
+ }
+ }
+
+ // Requires a custom validate() method, but fetches and stores the keys from the result set for further processing
+ protected abstract class CqlRunOpFetchKeys extends CqlRunOp<byte[][]>
+ {
+
+ protected CqlRunOpFetchKeys(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ super(client, query, queryId, KeysHandler.INSTANCE, params, key);
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return result.length;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return result.length;
+ }
+ }
+
+ protected final class CqlRunOpMatchResults extends CqlRunOp<ByteBuffer[][]>
+ {
+
+ final List<List<ByteBuffer>> 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<Object> params, ByteBuffer key, List<List<ByteBuffer>> expect)
+ {
+ super(client, query, queryId, RowsHandler.INSTANCE, params, key);
+ this.expect = expect;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return result == null ? 0 : result.length;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return result == null ? 0 : result.length;
+ }
+
+ public boolean validate(ByteBuffer[][] result)
+ {
+ if (result.length != expect.size())
+ return false;
+ for (int i = 0 ; i < result.length ; i++)
+ if (expect.get(i) != null && !expect.get(i).equals(Arrays.asList(result[i])))
+ return false;
+ return true;
+ }
+ }
+
+ // Cql
+ protected abstract class CqlRunOp<V> implements RunOp
+ {
+
+ final ClientWrapper client;
+ final String query;
+ final Object queryId;
+ final List<Object> params;
+ final ByteBuffer key;
+ final ResultHandler<V> handler;
+ V result;
+
+ private CqlRunOp(ClientWrapper client, String query, Object queryId, ResultHandler<V> handler, List<Object> params, ByteBuffer key)
+ {
+ this.client = client;
+ this.query = query;
+ this.queryId = queryId;
+ this.handler = handler;
+ this.params = params;
+ this.key = key;
+ }
+
+ @Override
+ public boolean run() throws Exception
+ {
+ return queryId != null
+ ? validate(result = client.execute(queryId, key, params, handler))
+ : validate(result = client.execute(query, key, params, handler));
+ }
+
+ public abstract boolean validate(V result);
+
+ }
+
+
+ /// LOTS OF WRAPPING/UNWRAPPING NONSENSE
+
+
+ @Override
+ public void run(final ThriftClient client) throws IOException
+ {
+ run(wrap(client));
+ }
+
+ @Override
+ public void run(SimpleClient client) throws IOException
+ {
+ run(wrap(client));
+ }
+
+ @Override
+ public void run(JavaDriverClient client) throws IOException
+ {
+ run(wrap(client));
+ }
+
+ public ClientWrapper wrap(ThriftClient client)
+ {
+ return isCql3()
+ ? new Cql3CassandraClientWrapper(client)
+ : new Cql2CassandraClientWrapper(client);
+
+ }
+
+ public ClientWrapper wrap(JavaDriverClient client)
+ {
+ return new JavaDriverWrapper(client);
+ }
+
+ public ClientWrapper wrap(SimpleClient client)
+ {
+ return new SimpleClientWrapper(client);
+ }
+
+ protected interface ClientWrapper
+ {
+ Object createPreparedStatement(String cqlQuery) throws TException;
+ <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
+ <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
+ }
+
+ private final class JavaDriverWrapper implements ClientWrapper
+ {
+ final JavaDriverClient client;
+ private JavaDriverWrapper(JavaDriverClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ String formattedQuery = formatCqlQuery(query, queryParams, isCql3());
+ return handler.javaDriverHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ return handler.javaDriverHandler().apply(
+ client.executePrepared(
+ (PreparedStatement) preparedStatementId,
+ queryParams,
+ ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery)
+ {
+ return client.prepare(cqlQuery);
+ }
+ }
+
+ private final class SimpleClientWrapper implements ClientWrapper
+ {
+ final SimpleClient client;
+ private SimpleClientWrapper(SimpleClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ String formattedQuery = formatCqlQuery(query, queryParams, isCql3());
+ return handler.thriftHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ return handler.thriftHandler().apply(
+ client.executePrepared(
+ (byte[]) preparedStatementId,
+ toByteBufferParams(queryParams),
+ ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery)
+ {
+ return client.prepare(cqlQuery).statementId.bytes;
+ }
+ }
+
+ // client wrapper for Cql3
+ private final class Cql3CassandraClientWrapper implements ClientWrapper
+ {
+ final ThriftClient client;
+ private Cql3CassandraClientWrapper(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ String formattedQuery = formatCqlQuery(query, queryParams, true);
+ return handler.simpleNativeHandler().apply(
+ client.execute_cql3_query(formattedQuery, key, Compression.NONE, settings.command.consistencyLevel)
+ );
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ Integer id = (Integer) preparedStatementId;
+ return handler.simpleNativeHandler().apply(
+ client.execute_prepared_cql3_query(id, key, toByteBufferParams(queryParams), settings.command.consistencyLevel)
+ );
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery) throws TException
+ {
+ return client.prepare_cql3_query(cqlQuery, Compression.NONE);
+ }
+ }
+
+ // client wrapper for Cql2
+ private final class Cql2CassandraClientWrapper implements ClientWrapper
+ {
+ final ThriftClient client;
+ private Cql2CassandraClientWrapper(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ String formattedQuery = formatCqlQuery(query, queryParams, false);
+ return handler.simpleNativeHandler().apply(
+ client.execute_cql_query(formattedQuery, key, Compression.NONE)
+ );
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ Integer id = (Integer) preparedStatementId;
+ return handler.simpleNativeHandler().apply(
+ client.execute_prepared_cql_query(id, key, toByteBufferParams(queryParams))
+ );
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery) throws TException
+ {
+ return client.prepare_cql_query(cqlQuery, Compression.NONE);
+ }
+ }
+
+ // interface for building functions to standardise results from each client
+ protected static interface ResultHandler<V>
+ {
+ Function<ResultSet, V> javaDriverHandler();
+ Function<ResultMessage, V> thriftHandler();
+ Function<CqlResult, V> simpleNativeHandler();
+ }
+
+ protected static class RowCountHandler implements ResultHandler<Integer>
+ {
+ static final RowCountHandler INSTANCE = new RowCountHandler();
+
+ @Override
+ public Function<ResultSet, Integer> javaDriverHandler()
+ {
+ return new Function<ResultSet, Integer>()
+ {
+ @Override
+ public Integer apply(ResultSet rows)
+ {
+ if (rows == null)
+ return 0;
+ return rows.all().size();
+ }
+ };
+ }
+
+ @Override
+ public Function<ResultMessage, Integer> thriftHandler()
+ {
+ return new Function<ResultMessage, Integer>()
+ {
+ @Override
+ public Integer apply(ResultMessage result)
+ {
+ return result instanceof ResultMessage.Rows ? ((ResultMessage.Rows) result).result.size() : 0;
+ }
+ };
+ }
+
+ @Override
+ public Function<CqlResult, Integer> simpleNativeHandler()
+ {
+ return new Function<CqlResult, Integer>()
+ {
+
+ @Override
+ public Integer apply(CqlResult result)
+ {
+ switch (result.getType())
+ {
+ case ROWS:
+ return result.getRows().size();
+ default:
+ return 1;
+ }
+ }
+ };
+ }
+
+ }
+
+ // Processes results from each client into an array of all key bytes returned
+ protected static final class RowsHandler implements ResultHandler<ByteBuffer[][]>
+ {
+ static final RowsHandler INSTANCE = new RowsHandler();
+
+ @Override
+ public Function<ResultSet, ByteBuffer[][]> javaDriverHandler()
+ {
+ return new Function<ResultSet, ByteBuffer[][]>()
+ {
+
+ @Override
+ public ByteBuffer[][] apply(ResultSet result)
+ {
+ if (result == null)
+ return new ByteBuffer[0][];
+ List<Row> rows = result.all();
+
+ ByteBuffer[][] r = new ByteBuffer[rows.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ {
+ Row row = rows.get(i);
+ r[i] = new ByteBuffer[row.getColumnDefinitions().size()];
+ for (int j = 0 ; j < row.getColumnDefinitions().size() ; j++)
+ r[i][j] = row.getBytes(j);
+ }
+ return r;
+ }
+ };
+ }
+
+ @Override
+ public Function<ResultMessage, ByteBuffer[][]> thriftHandler()
+ {
+ return new Function<ResultMessage, ByteBuffer[][]>()
+ {
+
+ @Override
+ public ByteBuffer[][] apply(ResultMessage result)
+ {
+ if (!(result instanceof ResultMessage.Rows))
+ return new ByteBuffer[0][];
+
+ ResultMessage.Rows rows = ((ResultMessage.Rows) result);
+ ByteBuffer[][] r = new ByteBuffer[rows.result.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ {
+ List<ByteBuffer> row = rows.result.rows.get(i);
+ r[i] = new ByteBuffer[row.size()];
+ for (int j = 0 ; j < row.size() ; j++)
+ r[i][j] = row.get(j);
+ }
+ return r;
+ }
+ };
+ }
+
+ @Override
+ public Function<CqlResult, ByteBuffer[][]> simpleNativeHandler()
+ {
+ return new Function<CqlResult, ByteBuffer[][]>()
+ {
+
+ @Override
+ public ByteBuffer[][] apply(CqlResult result)
+ {
+ ByteBuffer[][] r = new ByteBuffer[result.getRows().size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ {
+ CqlRow row = result.getRows().get(i);
+ r[i] = new ByteBuffer[row.getColumns().size()];
+ for (int j = 0 ; j < r[i].length ; j++)
+ r[i][j] = ByteBuffer.wrap(row.getColumns().get(j).getValue());
+ }
+ return r;
+ }
+ };
+ }
+
+ }
+ // Processes results from each client into an array of all key bytes returned
+ protected static final class KeysHandler implements ResultHandler<byte[][]>
+ {
+ static final KeysHandler INSTANCE = new KeysHandler();
+
+ @Override
+ public Function<ResultSet, byte[][]> javaDriverHandler()
+ {
+ return new Function<ResultSet, byte[][]>()
+ {
+
+ @Override
+ public byte[][] apply(ResultSet result)
+ {
+
+ if (result == null)
+ return new byte[0][];
+ List<Row> rows = result.all();
+ byte[][] r = new byte[rows.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ r[i] = rows.get(i).getBytes(0).array();
+ return r;
+ }
+ };
+ }
+
+ @Override
+ public Function<ResultMessage, byte[][]> thriftHandler()
+ {
+ return new Function<ResultMessage, byte[][]>()
+ {
+
+ @Override
+ public byte[][] apply(ResultMessage result)
+ {
+ if (result instanceof ResultMessage.Rows)
+ {
+ ResultMessage.Rows rows = ((ResultMessage.Rows) result);
+ byte[][] r = new byte[rows.result.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ r[i] = rows.result.rows.get(i).get(0).array();
+ return r;
+ }
+ return null;
+ }
+ };
+ }
+
+ @Override
+ public Function<CqlResult, byte[][]> simpleNativeHandler()
+ {
+ return new Function<CqlResult, byte[][]>()
+ {
+
+ @Override
+ public byte[][] apply(CqlResult result)
+ {
+ byte[][] r = new byte[result.getRows().size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ r[i] = result.getRows().get(i).getKey();
+ return r;
+ }
+ };
+ }
+
+ }
+
+ private static String getUnQuotedCqlBlob(ByteBuffer term, boolean isCQL3)
+ {
+ return isCQL3
+ ? "0x" + ByteBufferUtil.bytesToHex(term)
+ : ByteBufferUtil.bytesToHex(term);
+ }
+
+ /**
+ * Constructs a CQL query string by replacing instances of the character
+ * '?', with the corresponding parameter.
+ *
+ * @param query base query string to format
+ * @param parms sequence of string query parameters
+ * @return formatted CQL query string
+ */
+ private static String formatCqlQuery(String query, List<Object> parms, boolean isCql3)
+ {
+ int marker, position = 0;
+ StringBuilder result = new StringBuilder();
+
+ if (-1 == (marker = query.indexOf('?')) || parms.size() == 0)
+ return query;
+
+ for (Object parm : parms)
+ {
+ result.append(query.substring(position, marker));
+ 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)))
+ break;
+ }
+
+ if (position < query.length())
+ result.append(query.substring(position));
+
+ return result.toString();
+ }
+
+ private static List<ByteBuffer> toByteBufferParams(List<Object> params)
+ {
+ List<ByteBuffer> 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 settings.mode.cqlVersion == CqlVersion.CQL3
+ ? "\"" + string + "\""
+ : string;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
new file mode 100644
index 0000000..3a7f75a
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
@@ -0,0 +1,87 @@
+package org.apache.cassandra.stress.operations.predefined;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public class CqlReader extends CqlOperation<ByteBuffer[][]>
+{
+
+ public CqlReader(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.READ, timer, generator, settings);
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ StringBuilder query = new StringBuilder("SELECT ");
+
+ if (settings.columns.slice)
+ {
+ if (isCql2())
+ query.append("FIRST ").append(settings.columns.maxColumnsPerKey).append(" ''..''");
+ else
+ query.append("*");
+ }
+ else
+ {
+ for (int i = 0; i < settings.columns.maxColumnsPerKey ; i++)
+ {
+ if (i > 0)
+ query.append(",");
+ query.append(wrapInQuotesIfRequired(settings.columns.namestrs.get(i)));
+ }
+ }
+
+ query.append(" FROM ").append(wrapInQuotesIfRequired(type.table));
+
+ if (isCql2())
+ query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
+ query.append(" WHERE KEY=?");
+ return query.toString();
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ return Collections.<Object>singletonList(ByteBuffer.wrap(key));
+ }
+
+ @Override
+ protected CqlRunOp<ByteBuffer[][]> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ List<ByteBuffer> expectRow = getColumnValues();
+ return new CqlRunOpMatchResults(client, query, queryId, params, key, Arrays.asList(expectRow));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
new file mode 100644
index 0000000..7f6412b
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
@@ -0,0 +1,248 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+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.Operation;
+import org.apache.cassandra.stress.StressMetrics;
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.DistributionFixed;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.Row;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.CqlVersion;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.ColumnParent;
+import org.apache.cassandra.thrift.SlicePredicate;
+import org.apache.cassandra.thrift.SliceRange;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public abstract class PredefinedOperation extends Operation
+{
+ public final Command type;
+ private final Distribution columnCount;
+ private Object cqlCache;
+
+ public PredefinedOperation(Command type, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(timer, generator, settings, new DistributionFixed(1));
+ this.type = type;
+ this.columnCount = settings.columns.countDistribution.get();
+ }
+
+ public boolean isCql3()
+ {
+ return settings.mode.cqlVersion == CqlVersion.CQL3;
+ }
+ public boolean isCql2()
+ {
+ return settings.mode.cqlVersion == CqlVersion.CQL2;
+ }
+ public Object getCqlCache()
+ {
+ return cqlCache;
+ }
+ public void storeCqlCache(Object val)
+ {
+ cqlCache = val;
+ }
+
+ protected ByteBuffer getKey()
+ {
+ return (ByteBuffer) partitions.get(0).getPartitionKey(0);
+ }
+
+ final class ColumnSelection
+ {
+ final int[] indices;
+ final int lb, ub;
+ private ColumnSelection(int[] indices, int lb, int ub)
+ {
+ this.indices = indices;
+ this.lb = lb;
+ this.ub = ub;
+ }
+
+ public <V> List<V> select(List<V> in)
+ {
+ List<V> out = new ArrayList<>();
+ if (indices != null)
+ {
+ for (int i : indices)
+ out.add(in.get(i));
+ }
+ else
+ {
+ out.addAll(in.subList(lb, ub));
+ }
+ return out;
+ }
+
+ int count()
+ {
+ return indices != null ? indices.length : ub - lb;
+ }
+
+ SlicePredicate predicate()
+ {
+ final SlicePredicate predicate = new SlicePredicate();
+ if (indices == null)
+ {
+ predicate.setSlice_range(new SliceRange()
+ .setStart(settings.columns.names.get(lb))
+ .setFinish(new byte[] {})
+ .setReversed(false)
+ .setCount(count())
+ );
+ }
+ else
+ predicate.setColumn_names(select(settings.columns.names));
+ return predicate;
+
+ }
+ }
+
+ public String toString()
+ {
+ return type.toString();
+ }
+
+ ColumnSelection select()
+ {
+ if (settings.columns.slice)
+ {
+ int count = (int) columnCount.next();
+ int start;
+ if (count == settings.columns.maxColumnsPerKey)
+ start = 0;
+ else
+ start = 1 + ThreadLocalRandom.current().nextInt(settings.columns.maxColumnsPerKey - count);
+ return new ColumnSelection(null, start, start + count);
+ }
+
+ int count = (int) columnCount.next();
+ int totalCount = settings.columns.names.size();
+ if (count == settings.columns.names.size())
+ return new ColumnSelection(null, 0, count);
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ int[] indices = new int[count];
+ int c = 0, o = 0;
+ while (c < count && count + o < totalCount)
+ {
+ int leeway = totalCount - (count + o);
+ int spreadover = count - c;
+ o += Math.round(rnd.nextDouble() * (leeway / (double) spreadover));
+ indices[c] = o + c;
+ c++;
+ }
+ while (c < count)
+ {
+ indices[c] = o + c;
+ c++;
+ }
+ return new ColumnSelection(indices, 0, 0);
+ }
+
+ protected List<ByteBuffer> getColumnValues()
+ {
+ return getColumnValues(new ColumnSelection(null, 0, settings.columns.names.size()));
+ }
+
+ protected List<ByteBuffer> getColumnValues(ColumnSelection columns)
+ {
+ Row row = partitions.get(0).iterator(1).batch(1f).iterator().next();
+ ByteBuffer[] r = new ByteBuffer[columns.count()];
+ int c = 0;
+ if (columns.indices != null)
+ for (int i : columns.indices)
+ r[c++] = (ByteBuffer) row.get(i);
+ else
+ for (int i = columns.lb ; i < columns.ub ; i++)
+ r[c++] = (ByteBuffer) row.get(i);
+ return Arrays.asList(r);
+ }
+
+ public static Operation operation(Command type, Timer timer, PartitionGenerator generator, StressSettings settings, DistributionFactory counteradd)
+ {
+ switch (type)
+ {
+ case READ:
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftReader(timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlReader(timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+
+ case COUNTER_READ:
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftCounterGetter(timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlCounterGetter(timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ case WRITE:
+
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftInserter(timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlInserter(timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ case COUNTER_WRITE:
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftCounterAdder(counteradd, timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlCounterAdder(counteradd, timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ throw new UnsupportedOperationException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterAdder.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterAdder.java
new file mode 100644
index 0000000..ee766c3
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterAdder.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.*;
+
+public class ThriftCounterAdder extends PredefinedOperation
+{
+
+ final Distribution counteradd;
+ public ThriftCounterAdder(DistributionFactory counteradd, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_WRITE, timer, generator, settings);
+ this.counteradd = counteradd.get();
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ List<CounterColumn> columns = new ArrayList<>();
+ for (ByteBuffer name : select().select(settings.columns.names))
+ columns.add(new CounterColumn(name, counteradd.next()));
+
+ List<Mutation> mutations = new ArrayList<>(columns.size());
+ for (CounterColumn c : columns)
+ {
+ ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setCounter_column(c);
+ mutations.add(new Mutation().setColumn_or_supercolumn(cosc));
+ }
+ Map<String, List<Mutation>> row = Collections.singletonMap(type.table, mutations);
+
+ final ByteBuffer key = getKey();
+ final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
+
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ client.batch_mutate(record, settings.command.consistencyLevel);
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterGetter.java
new file mode 100644
index 0000000..10c6aab
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterGetter.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+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.SlicePredicate;
+
+public class ThriftCounterGetter extends PredefinedOperation
+{
+ public ThriftCounterGetter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_READ, timer, generator, settings);
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ final SlicePredicate predicate = select().predicate();
+ final ByteBuffer key = getKey();
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ List<?> r = client.get_slice(key, new ColumnParent(type.table), predicate, settings.command.consistencyLevel);
+ return r != null && r.size() > 0;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
new file mode 100644
index 0000000..5c2acfe
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cassandra.db.marshal.TimeUUIDType;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.*;
+import org.apache.cassandra.utils.FBUtilities;
+import org.apache.cassandra.utils.UUIDGen;
+
+public final class ThriftInserter extends PredefinedOperation
+{
+
+ public ThriftInserter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.WRITE, timer, generator, settings);
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ final ByteBuffer key = getKey();
+ final List<Column> columns = getColumns();
+
+ List<Mutation> mutations = new ArrayList<>(columns.size());
+ for (Column c : columns)
+ {
+ ColumnOrSuperColumn column = new ColumnOrSuperColumn().setColumn(c);
+ mutations.add(new Mutation().setColumn_or_supercolumn(column));
+ }
+ Map<String, List<Mutation>> row = Collections.singletonMap(type.table, mutations);
+
+ final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
+
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ client.batch_mutate(record, settings.command.consistencyLevel);
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+ protected List<Column> getColumns()
+ {
+ final ColumnSelection selection = select();
+ final List<ByteBuffer> values = getColumnValues(selection);
+ final List<Column> columns = new ArrayList<>(values.size());
+ final List<ByteBuffer> names = select().select(settings.columns.names);
+ for (int i = 0 ; i < values.size() ; i++)
+ columns.add(new Column(names.get(i))
+ .setValue(values.get(i))
+ .setTimestamp(FBUtilities.timestampMicros()));
+ return columns;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftReader.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftReader.java
new file mode 100644
index 0000000..276d8c5
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftReader.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.ColumnOrSuperColumn;
+import org.apache.cassandra.thrift.ColumnParent;
+import org.apache.cassandra.thrift.SlicePredicate;
+import org.apache.cassandra.thrift.SuperColumn;
+
+public final class ThriftReader extends PredefinedOperation
+{
+
+ public ThriftReader(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.READ, timer, generator, settings);
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ final ColumnSelection select = select();
+ final ByteBuffer key = getKey();
+ final List<ByteBuffer> expect = getColumnValues(select);
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ List<ColumnOrSuperColumn> row = client.get_slice(key, new ColumnParent(type.table), select.predicate(), settings.command.consistencyLevel);
+ if (expect == null)
+ return !row.isEmpty();
+ if (row == null)
+ return false;
+ if (row.size() != expect.size())
+ return false;
+ for (int i = 0 ; i < row.size() ; i++)
+ if (!row.get(i).getColumn().bufferForValue().equals(expect.get(i)))
+ return false;
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaInsert.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaInsert.java b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaInsert.java
new file mode 100644
index 0000000..7c5efac
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaInsert.java
@@ -0,0 +1,144 @@
+package org.apache.cassandra.stress.operations.userdefined;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.datastax.driver.core.BatchStatement;
+import com.datastax.driver.core.BoundStatement;
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.Statement;
+import org.apache.cassandra.db.ConsistencyLevel;
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.Partition;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.RatioDistribution;
+import org.apache.cassandra.stress.generate.Row;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.settings.ValidationType;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+
+public class SchemaInsert extends SchemaStatement
+{
+
+ private final BatchStatement.Type batchType;
+ private final RatioDistribution perVisit;
+ private final RatioDistribution perBatch;
+
+ public SchemaInsert(Timer timer, PartitionGenerator generator, StressSettings settings, Distribution partitionCount, RatioDistribution perVisit, RatioDistribution perBatch, Integer thriftId, PreparedStatement statement, ConsistencyLevel cl, BatchStatement.Type batchType)
+ {
+ super(timer, generator, settings, partitionCount, statement, thriftId, cl, ValidationType.NOT_FAIL);
+ this.batchType = batchType;
+ this.perVisit = perVisit;
+ this.perBatch = perBatch;
+ }
+
+ private class JavaDriverRun extends Runner
+ {
+ final JavaDriverClient client;
+
+ private JavaDriverRun(JavaDriverClient client)
+ {
+ this.client = client;
+ }
+
+ public boolean run() throws Exception
+ {
+ Partition.RowIterator[] iterators = new Partition.RowIterator[partitions.size()];
+ for (int i = 0 ; i < iterators.length ; i++)
+ iterators[i] = partitions.get(i).iterator(perVisit.next());
+ List<BoundStatement> stmts = new ArrayList<>();
+ partitionCount = partitions.size();
+
+ boolean done;
+ do
+ {
+ done = true;
+ stmts.clear();
+ for (Partition.RowIterator iterator : iterators)
+ {
+ if (iterator.done())
+ continue;
+
+ for (Row row : iterator.batch(perBatch.next()))
+ stmts.add(bindRow(row));
+
+ done &= iterator.done();
+ }
+
+ rowCount += stmts.size();
+
+ Statement stmt;
+ if (stmts.size() == 1)
+ {
+ stmt = stmts.get(0);
+ }
+ else
+ {
+ BatchStatement batch = new BatchStatement(batchType);
+ batch.setConsistencyLevel(JavaDriverClient.from(cl));
+ batch.addAll(stmts);
+ stmt = batch;
+ }
+ validate(client.getSession().execute(stmt));
+
+ } while (!done);
+
+ return true;
+ }
+ }
+
+ private class ThriftRun extends Runner
+ {
+ final ThriftClient client;
+
+ private ThriftRun(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ public boolean run() throws Exception
+ {
+ Partition.RowIterator[] iterators = new Partition.RowIterator[partitions.size()];
+ for (int i = 0 ; i < iterators.length ; i++)
+ iterators[i] = partitions.get(i).iterator(perVisit.next());
+ partitionCount = partitions.size();
+
+ boolean done;
+ do
+ {
+ done = true;
+ for (Partition.RowIterator iterator : iterators)
+ {
+ if (iterator.done())
+ continue;
+
+ for (Row row : iterator.batch(perBatch.next()))
+ {
+ validate(client.execute_prepared_cql3_query(thriftId, iterator.partition().getToken(), thriftRowArgs(row), settings.command.consistencyLevel));
+ rowCount += 1;
+ }
+
+ done &= iterator.done();
+ }
+ } while (!done);
+
+ return true;
+ }
+ }
+
+ @Override
+ public void run(JavaDriverClient client) throws IOException
+ {
+ timeWithRetry(new JavaDriverRun(client));
+ }
+
+ @Override
+ public void run(ThriftClient client) throws IOException
+ {
+ timeWithRetry(new ThriftRun(client));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaQuery.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaQuery.java b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaQuery.java
new file mode 100644
index 0000000..9cec39b
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaQuery.java
@@ -0,0 +1,86 @@
+package org.apache.cassandra.stress.operations.userdefined;
+
+import java.io.IOException;
+
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.ResultSet;
+import org.apache.cassandra.db.ConsistencyLevel;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.OptionDistribution;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.settings.ValidationType;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.CqlResult;
+import org.apache.cassandra.thrift.ThriftConversion;
+
+public class SchemaQuery extends SchemaStatement
+{
+
+ public SchemaQuery(Timer timer, PartitionGenerator generator, StressSettings settings, Integer thriftId, PreparedStatement statement, ConsistencyLevel cl, ValidationType validationType)
+ {
+ super(timer, generator, settings, OptionDistribution.get("fixed(1)").get(), statement, thriftId, cl, validationType);
+ }
+
+ int execute(JavaDriverClient client) throws Exception
+ {
+ return client.getSession().execute(bindRandom(partitions.get(0))).all().size();
+ }
+
+ int execute(ThriftClient client) throws Exception
+ {
+ return client.execute_prepared_cql3_query(thriftId, partitions.get(0).getToken(), thriftRandomArgs(partitions.get(0)), ThriftConversion.toThrift(cl)).getRowsSize();
+ }
+
+ private class JavaDriverRun extends Runner
+ {
+ final JavaDriverClient client;
+
+ private JavaDriverRun(JavaDriverClient client)
+ {
+ this.client = client;
+ }
+
+ public boolean run() throws Exception
+ {
+ ResultSet rs = client.getSession().execute(bindRandom(partitions.get(0)));
+ validate(rs);
+ rowCount = rs.all().size();
+ partitionCount = Math.min(1, rowCount);
+ return true;
+ }
+ }
+
+ private class ThriftRun extends Runner
+ {
+ final ThriftClient client;
+
+ private ThriftRun(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ public boolean run() throws Exception
+ {
+ CqlResult rs = client.execute_prepared_cql3_query(thriftId, partitions.get(0).getToken(), thriftRandomArgs(partitions.get(0)), ThriftConversion.toThrift(cl));
+ validate(rs);
+ rowCount = rs.getRowsSize();
+ partitionCount = Math.min(1, rowCount);
+ return true;
+ }
+ }
+
+ @Override
+ public void run(JavaDriverClient client) throws IOException
+ {
+ timeWithRetry(new JavaDriverRun(client));
+ }
+
+ @Override
+ public void run(ThriftClient client) throws IOException
+ {
+ timeWithRetry(new ThriftRun(client));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaStatement.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaStatement.java b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaStatement.java
new file mode 100644
index 0000000..aac40c5
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaStatement.java
@@ -0,0 +1,164 @@
+package org.apache.cassandra.stress.operations.userdefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import com.datastax.driver.core.BoundStatement;
+import com.datastax.driver.core.ColumnDefinitions;
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.ResultSet;
+import org.apache.cassandra.db.ConsistencyLevel;
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.Partition;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.Row;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.settings.ValidationType;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.CqlResult;
+import org.apache.cassandra.transport.SimpleClient;
+
+public abstract class SchemaStatement extends Operation
+{
+
+ final PartitionGenerator generator;
+ private final PreparedStatement statement;
+ final Integer thriftId;
+ final ConsistencyLevel cl;
+ final ValidationType validationType;
+ private final int[] argumentIndex;
+ private final Object[] bindBuffer;
+ private final Object[][] randomBuffer;
+ private final Random random = new Random();
+
+ public SchemaStatement(Timer timer, PartitionGenerator generator, StressSettings settings, Distribution partitionCount,
+ PreparedStatement statement, Integer thriftId, ConsistencyLevel cl, ValidationType validationType)
+ {
+ super(timer, generator, settings, partitionCount);
+ this.generator = generator;
+ this.statement = statement;
+ this.thriftId = thriftId;
+ this.cl = cl;
+ this.validationType = validationType;
+ argumentIndex = new int[statement.getVariables().size()];
+ bindBuffer = new Object[argumentIndex.length];
+ randomBuffer = new Object[argumentIndex.length][argumentIndex.length];
+ int i = 0;
+ for (ColumnDefinitions.Definition definition : statement.getVariables())
+ argumentIndex[i++] = generator.indexOf(definition.getName());
+ }
+
+ private int filLRandom(Partition partition)
+ {
+ int c = 0;
+ for (Row row : partition.iterator(randomBuffer.length).batch(1f))
+ {
+ Object[] randomRow = randomBuffer[c++];
+ for (int i = 0 ; i < argumentIndex.length ; i++)
+ randomRow[i] = row.get(argumentIndex[i]);
+ if (c >= randomBuffer.length)
+ break;
+ }
+ return c;
+ }
+
+ BoundStatement bindRandom(Partition partition)
+ {
+ int c = filLRandom(partition);
+ for (int i = 0 ; i < argumentIndex.length ; i++)
+ {
+ int argIndex = argumentIndex[i];
+ bindBuffer[i] = randomBuffer[argIndex < 0 ? 0 : random.nextInt(c)][i];
+ }
+ return statement.bind(bindBuffer);
+ }
+
+ BoundStatement bindRow(Row row)
+ {
+ for (int i = 0 ; i < argumentIndex.length ; i++)
+ bindBuffer[i] = row.get(argumentIndex[i]);
+ return statement.bind(bindBuffer);
+ }
+
+ List<ByteBuffer> thriftRowArgs(Row row)
+ {
+ List<ByteBuffer> args = new ArrayList<>();
+ for (int i : argumentIndex)
+ args.add(generator.convert(i, row.get(i)));
+ return args;
+ }
+
+ List<ByteBuffer> thriftRandomArgs(Partition partition)
+ {
+ List<ByteBuffer> args = new ArrayList<>();
+ int c = filLRandom(partition);
+ for (int i = 0 ; i < argumentIndex.length ; i++)
+ {
+ int argIndex = argumentIndex[i];
+ args.add(generator.convert(argIndex, randomBuffer[argIndex < 0 ? 0 : random.nextInt(c)][i]));
+ }
+ return args;
+ }
+
+ void validate(ResultSet rs)
+ {
+ switch (validationType)
+ {
+ case NOT_FAIL:
+ return;
+ case NON_ZERO:
+ if (rs.all().size() == 0)
+ throw new IllegalStateException("Expected non-zero results");
+ break;
+ default:
+ throw new IllegalStateException("Unsupported validation type");
+ }
+ }
+
+ void validate(CqlResult rs)
+ {
+ switch (validationType)
+ {
+ case NOT_FAIL:
+ return;
+ case NON_ZERO:
+ if (rs.getRowsSize() == 0)
+ throw new IllegalStateException("Expected non-zero results");
+ break;
+ default:
+ throw new IllegalStateException("Unsupported validation type");
+ }
+ }
+
+ @Override
+ public void run(SimpleClient client) throws IOException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ abstract class Runner implements RunOp
+ {
+ int partitionCount;
+ int rowCount;
+
+ @Override
+ public int partitionCount()
+ {
+ return partitionCount;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return rowCount;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/Command.java
----------------------------------------------------------------------
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 ac10014..7138cbb 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/Command.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/Command.java
@@ -41,19 +41,6 @@ public enum Command
"Interleaving of any basic commands, with configurable ratio and distribution - the cluster must first be populated by a write test",
CommandCategory.MIXED
),
- RANGE_SLICE(false, "Standard1", "Super1",
- "Range slice queries - the cluster must first be populated by a write test",
- CommandCategory.MULTI
- ),
- INDEXED_RANGE_SLICE(false, "Standard1", "Super1",
- "Range slice queries through a secondary index. The cluster must first be populated by a write test, with indexing enabled.",
- CommandCategory.BASIC
- ),
- READ_MULTI(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
- ),
COUNTER_WRITE(true, "Counter1", "SuperCounter1",
"counter_add",
"Multiple concurrent updates of counters.",
@@ -64,6 +51,10 @@ public enum Command
"Multiple concurrent reads of counters. The cluster must first be populated by a counterwrite test.",
CommandCategory.BASIC
),
+ USER(true, null, null,
+ "Interleaving of user provided queries, with configurable ratio and distribution",
+ CommandCategory.USER
+ ),
HELP(false, null, null, "-?", "Print help for a command or option", null),
PRINT(false, null, null, "Inspect the output of a distribution definition", null),
@@ -136,11 +127,12 @@ public enum Command
}
switch (category)
{
+ case USER:
+ return SettingsCommandUser.helpPrinter();
case BASIC:
- case MULTI:
- return SettingsCommand.helpPrinter(this);
+ return SettingsCommandPreDefined.helpPrinter(this);
case MIXED:
- return SettingsCommandMixed.helpPrinter();
+ return SettingsCommandPreDefinedMixed.helpPrinter();
}
throw new AssertionError();
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java b/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java
index 4372f59..e9dd946 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java
@@ -24,6 +24,6 @@ package org.apache.cassandra.stress.settings;
public enum CommandCategory
{
BASIC,
- MULTI,
- MIXED
+ MIXED,
+ USER
}
[11/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java
deleted file mode 100644
index 021c4e8..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftRangeSlicer.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.util.ThriftClient;
-import org.apache.cassandra.thrift.ColumnParent;
-import org.apache.cassandra.thrift.KeyRange;
-import org.apache.cassandra.thrift.SlicePredicate;
-import org.apache.cassandra.thrift.SliceRange;
-import org.apache.cassandra.utils.ByteBufferUtil;
-
-public final class ThriftRangeSlicer extends Operation
-{
-
- public ThriftRangeSlicer(State state, long index)
- {
- super(state, index);
- }
-
- @Override
- public void run(final ThriftClient client) throws IOException
- {
- final SlicePredicate predicate = new SlicePredicate()
- .setSlice_range(
- new SliceRange(
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- false,
- state.settings.columns.maxColumnsPerKey
- )
- );
-
- final ByteBuffer start = getKey();
- final KeyRange range =
- new KeyRange(state.settings.columns.maxColumnsPerKey)
- .setStart_key(start)
- .setEnd_key(ByteBufferUtil.EMPTY_BYTE_BUFFER)
- .setCount(state.settings.command.keysAtOnce);
-
- for (final ColumnParent parent : state.columnParents)
- {
- timeWithRetry(new RunOp()
- {
- private int count = 0;
- @Override
- public boolean run() throws Exception
- {
- return (count = client.get_range_slices(parent, predicate, range, state.settings.command.consistencyLevel).size()) != 0;
- }
-
- @Override
- public String key()
- {
- return new String(range.bufferForStart_key().array());
- }
-
- @Override
- public int keyCount()
- {
- return count;
- }
- });
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java
deleted file mode 100644
index dccf469..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftReader.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.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;
-import org.apache.cassandra.thrift.ColumnOrSuperColumn;
-import org.apache.cassandra.thrift.ColumnParent;
-import org.apache.cassandra.thrift.SlicePredicate;
-import org.apache.cassandra.thrift.SuperColumn;
-
-public final class ThriftReader extends Operation
-{
-
- public ThriftReader(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
- final SlicePredicate predicate = slicePredicate();
- final ByteBuffer key = getKey();
- final List<ByteBuffer> expect = state.rowGen.isDeterministic() ? generateColumnValues(key) : null;
- for (final ColumnParent parent : state.columnParents)
- {
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- List<ColumnOrSuperColumn> 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())
- return false;
- for (int i = 0 ; i < row.size() ; i++)
- if (!row.get(i).getColumn().bufferForValue().equals(expect.get(i)))
- return false;
- }
- else
- {
- for (ColumnOrSuperColumn col : row)
- {
- SuperColumn superColumn = col.getSuper_column();
- if (superColumn.getColumns().size() != expect.size())
- return false;
- for (int i = 0 ; i < expect.size() ; i++)
- if (!superColumn.getColumns().get(i).bufferForValue().equals(expect.get(i)))
- return false;
- }
- }
- return true;
- }
-
- @Override
- public String key()
- {
- return new String(key.array());
- }
-
- @Override
- public int keyCount()
- {
- return 1;
- }
- });
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
new file mode 100644
index 0000000..f794e75
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
@@ -0,0 +1,84 @@
+package org.apache.cassandra.stress.operations.predefined;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+
+public class CqlCounterAdder extends CqlOperation<Integer>
+{
+
+ final Distribution counteradd;
+ public CqlCounterAdder(DistributionFactory counteradd, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_WRITE, timer, generator, settings);
+ this.counteradd = counteradd.get();
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ String counterCF = isCql2() ? type.table : "Counter3";
+
+ StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(counterCF));
+
+ if (isCql2())
+ query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
+
+ query.append(" SET ");
+
+ // TODO : increment distribution subset of columns
+ for (int i = 0; i < settings.columns.maxColumnsPerKey; i++)
+ {
+ if (i > 0)
+ query.append(",");
+
+ query.append('C').append(i).append("=C").append(i).append("+?");
+ }
+ query.append(" WHERE KEY=?");
+ return query.toString();
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ final List<Object> list = new ArrayList<>();
+ for (int i = 0; i < settings.columns.maxColumnsPerKey; i++)
+ list.add(counteradd.next());
+ list.add(ByteBuffer.wrap(key));
+ return list;
+ }
+
+ @Override
+ protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ return new CqlRunOpAlwaysSucceed(client, query, queryId, params, key, 1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
new file mode 100644
index 0000000..94c8faf
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
@@ -0,0 +1,74 @@
+package org.apache.cassandra.stress.operations.predefined;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+
+public class CqlCounterGetter extends CqlOperation<Integer>
+{
+
+ public CqlCounterGetter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_READ, timer, generator, settings);
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ return Collections.<Object>singletonList(ByteBuffer.wrap(key));
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ StringBuilder query = new StringBuilder("SELECT ");
+
+ // TODO: obey slice/noslice option (instead of always slicing)
+ if (isCql2())
+ query.append("FIRST ").append(settings.columns.maxColumnsPerKey).append(" ''..''");
+ else
+ query.append("*");
+
+ String counterCF = isCql2() ? type.table : "Counter3";
+
+ query.append(" FROM ").append(wrapInQuotesIfRequired(counterCF));
+
+ if (isCql2())
+ query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
+
+ return query.append(" WHERE KEY=?").toString();
+ }
+
+ @Override
+ protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ return new CqlRunOpTestNonEmpty(client, query, queryId, params, key);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
new file mode 100644
index 0000000..c422f2b
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
@@ -0,0 +1,79 @@
+package org.apache.cassandra.stress.operations.predefined;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.utils.UUIDGen;
+
+public class CqlInserter extends CqlOperation<Integer>
+{
+
+ public CqlInserter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.WRITE, timer, generator, settings);
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(type.table));
+
+ if (isCql2())
+ query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
+
+ query.append(" SET ");
+
+ for (int i = 0 ; i < settings.columns.maxColumnsPerKey ; i++)
+ {
+ if (i > 0)
+ query.append(',');
+
+ query.append(wrapInQuotesIfRequired(settings.columns.namestrs.get(i))).append(" = ?");
+ }
+
+ query.append(" WHERE KEY=?");
+ return query.toString();
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ final ArrayList<Object> queryParams = new ArrayList<>();
+ List<ByteBuffer> values = getColumnValues();
+ queryParams.addAll(values);
+ queryParams.add(ByteBuffer.wrap(key));
+ return queryParams;
+ }
+
+ @Override
+ protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ return new CqlRunOpAlwaysSucceed(client, query, queryId, params, key, 1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
new file mode 100644
index 0000000..0264cd1
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
@@ -0,0 +1,714 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.google.common.base.Function;
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.StressMetrics;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.ConnectionStyle;
+import org.apache.cassandra.stress.settings.CqlVersion;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.Compression;
+import org.apache.cassandra.thrift.CqlResult;
+import org.apache.cassandra.thrift.CqlRow;
+import org.apache.cassandra.thrift.ThriftConversion;
+import org.apache.cassandra.transport.SimpleClient;
+import org.apache.cassandra.transport.messages.ResultMessage;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.thrift.TException;
+
+public abstract class CqlOperation<V> extends PredefinedOperation
+{
+
+ protected abstract List<Object> getQueryParameters(byte[] key);
+ protected abstract String buildQuery();
+ protected abstract CqlRunOp<V> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key);
+
+ public CqlOperation(Command type, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(type, timer, generator, settings);
+ if (settings.columns.variableColumnCount)
+ throw new IllegalStateException("Variable column counts are not implemented for CQL");
+ }
+
+ protected CqlRunOp<V> run(final ClientWrapper client, final List<Object> queryParams, final ByteBuffer key) throws IOException
+ {
+ final CqlRunOp<V> op;
+ if (settings.mode.style == ConnectionStyle.CQL_PREPARED)
+ {
+ final Object id;
+ Object idobj = getCqlCache();
+ if (idobj == null)
+ {
+ try
+ {
+ id = client.createPreparedStatement(buildQuery());
+ } catch (TException e)
+ {
+ throw new RuntimeException(e);
+ }
+ storeCqlCache(id);
+ }
+ else
+ id = idobj;
+
+ op = buildRunOp(client, null, id, queryParams, key);
+ }
+ else
+ {
+ final String query;
+ Object qobj = getCqlCache();
+ if (qobj == null)
+ storeCqlCache(query = buildQuery());
+ else
+ query = qobj.toString();
+
+ op = buildRunOp(client, query, null, queryParams, key);
+ }
+
+ timeWithRetry(op);
+ return op;
+ }
+
+ protected void run(final ClientWrapper client) throws IOException
+ {
+ final byte[] key = getKey().array();
+ final List<Object> queryParams = getQueryParameters(key);
+ run(client, queryParams, ByteBuffer.wrap(key));
+ }
+
+ // Classes to process Cql results
+
+ // Always succeeds so long as the query executes without error; provides a keyCount to increment on instantiation
+ protected final class CqlRunOpAlwaysSucceed extends CqlRunOp<Integer>
+ {
+
+ final int keyCount;
+
+ protected CqlRunOpAlwaysSucceed(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key, int keyCount)
+ {
+ super(client, query, queryId, RowCountHandler.INSTANCE, params, key);
+ this.keyCount = keyCount;
+ }
+
+ @Override
+ public boolean validate(Integer result)
+ {
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return keyCount;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return keyCount;
+ }
+ }
+
+ // Succeeds so long as the result set is nonempty, and the query executes without error
+ protected final class CqlRunOpTestNonEmpty extends CqlRunOp<Integer>
+ {
+
+ protected CqlRunOpTestNonEmpty(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ super(client, query, queryId, RowCountHandler.INSTANCE, params, key);
+ }
+
+ @Override
+ public boolean validate(Integer result)
+ {
+ return result > 0;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return result;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return result;
+ }
+ }
+
+ // Requires a custom validate() method, but fetches and stores the keys from the result set for further processing
+ protected abstract class CqlRunOpFetchKeys extends CqlRunOp<byte[][]>
+ {
+
+ protected CqlRunOpFetchKeys(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ super(client, query, queryId, KeysHandler.INSTANCE, params, key);
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return result.length;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return result.length;
+ }
+ }
+
+ protected final class CqlRunOpMatchResults extends CqlRunOp<ByteBuffer[][]>
+ {
+
+ final List<List<ByteBuffer>> 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<Object> params, ByteBuffer key, List<List<ByteBuffer>> expect)
+ {
+ super(client, query, queryId, RowsHandler.INSTANCE, params, key);
+ this.expect = expect;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return result == null ? 0 : result.length;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return result == null ? 0 : result.length;
+ }
+
+ public boolean validate(ByteBuffer[][] result)
+ {
+ if (result.length != expect.size())
+ return false;
+ for (int i = 0 ; i < result.length ; i++)
+ if (expect.get(i) != null && !expect.get(i).equals(Arrays.asList(result[i])))
+ return false;
+ return true;
+ }
+ }
+
+ // Cql
+ protected abstract class CqlRunOp<V> implements RunOp
+ {
+
+ final ClientWrapper client;
+ final String query;
+ final Object queryId;
+ final List<Object> params;
+ final ByteBuffer key;
+ final ResultHandler<V> handler;
+ V result;
+
+ private CqlRunOp(ClientWrapper client, String query, Object queryId, ResultHandler<V> handler, List<Object> params, ByteBuffer key)
+ {
+ this.client = client;
+ this.query = query;
+ this.queryId = queryId;
+ this.handler = handler;
+ this.params = params;
+ this.key = key;
+ }
+
+ @Override
+ public boolean run() throws Exception
+ {
+ return queryId != null
+ ? validate(result = client.execute(queryId, key, params, handler))
+ : validate(result = client.execute(query, key, params, handler));
+ }
+
+ public abstract boolean validate(V result);
+
+ }
+
+
+ /// LOTS OF WRAPPING/UNWRAPPING NONSENSE
+
+
+ @Override
+ public void run(final ThriftClient client) throws IOException
+ {
+ run(wrap(client));
+ }
+
+ @Override
+ public void run(SimpleClient client) throws IOException
+ {
+ run(wrap(client));
+ }
+
+ @Override
+ public void run(JavaDriverClient client) throws IOException
+ {
+ run(wrap(client));
+ }
+
+ public ClientWrapper wrap(ThriftClient client)
+ {
+ return isCql3()
+ ? new Cql3CassandraClientWrapper(client)
+ : new Cql2CassandraClientWrapper(client);
+
+ }
+
+ public ClientWrapper wrap(JavaDriverClient client)
+ {
+ return new JavaDriverWrapper(client);
+ }
+
+ public ClientWrapper wrap(SimpleClient client)
+ {
+ return new SimpleClientWrapper(client);
+ }
+
+ protected interface ClientWrapper
+ {
+ Object createPreparedStatement(String cqlQuery) throws TException;
+ <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
+ <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
+ }
+
+ private final class JavaDriverWrapper implements ClientWrapper
+ {
+ final JavaDriverClient client;
+ private JavaDriverWrapper(JavaDriverClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ String formattedQuery = formatCqlQuery(query, queryParams, isCql3());
+ return handler.javaDriverHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ return handler.javaDriverHandler().apply(
+ client.executePrepared(
+ (PreparedStatement) preparedStatementId,
+ queryParams,
+ ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery)
+ {
+ return client.prepare(cqlQuery);
+ }
+ }
+
+ private final class SimpleClientWrapper implements ClientWrapper
+ {
+ final SimpleClient client;
+ private SimpleClientWrapper(SimpleClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ String formattedQuery = formatCqlQuery(query, queryParams, isCql3());
+ return handler.thriftHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ return handler.thriftHandler().apply(
+ client.executePrepared(
+ (byte[]) preparedStatementId,
+ toByteBufferParams(queryParams),
+ ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery)
+ {
+ return client.prepare(cqlQuery).statementId.bytes;
+ }
+ }
+
+ // client wrapper for Cql3
+ private final class Cql3CassandraClientWrapper implements ClientWrapper
+ {
+ final ThriftClient client;
+ private Cql3CassandraClientWrapper(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ String formattedQuery = formatCqlQuery(query, queryParams, true);
+ return handler.simpleNativeHandler().apply(
+ client.execute_cql3_query(formattedQuery, key, Compression.NONE, settings.command.consistencyLevel)
+ );
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ Integer id = (Integer) preparedStatementId;
+ return handler.simpleNativeHandler().apply(
+ client.execute_prepared_cql3_query(id, key, toByteBufferParams(queryParams), settings.command.consistencyLevel)
+ );
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery) throws TException
+ {
+ return client.prepare_cql3_query(cqlQuery, Compression.NONE);
+ }
+ }
+
+ // client wrapper for Cql2
+ private final class Cql2CassandraClientWrapper implements ClientWrapper
+ {
+ final ThriftClient client;
+ private Cql2CassandraClientWrapper(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ String formattedQuery = formatCqlQuery(query, queryParams, false);
+ return handler.simpleNativeHandler().apply(
+ client.execute_cql_query(formattedQuery, key, Compression.NONE)
+ );
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ Integer id = (Integer) preparedStatementId;
+ return handler.simpleNativeHandler().apply(
+ client.execute_prepared_cql_query(id, key, toByteBufferParams(queryParams))
+ );
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery) throws TException
+ {
+ return client.prepare_cql_query(cqlQuery, Compression.NONE);
+ }
+ }
+
+ // interface for building functions to standardise results from each client
+ protected static interface ResultHandler<V>
+ {
+ Function<ResultSet, V> javaDriverHandler();
+ Function<ResultMessage, V> thriftHandler();
+ Function<CqlResult, V> simpleNativeHandler();
+ }
+
+ protected static class RowCountHandler implements ResultHandler<Integer>
+ {
+ static final RowCountHandler INSTANCE = new RowCountHandler();
+
+ @Override
+ public Function<ResultSet, Integer> javaDriverHandler()
+ {
+ return new Function<ResultSet, Integer>()
+ {
+ @Override
+ public Integer apply(ResultSet rows)
+ {
+ if (rows == null)
+ return 0;
+ return rows.all().size();
+ }
+ };
+ }
+
+ @Override
+ public Function<ResultMessage, Integer> thriftHandler()
+ {
+ return new Function<ResultMessage, Integer>()
+ {
+ @Override
+ public Integer apply(ResultMessage result)
+ {
+ return result instanceof ResultMessage.Rows ? ((ResultMessage.Rows) result).result.size() : 0;
+ }
+ };
+ }
+
+ @Override
+ public Function<CqlResult, Integer> simpleNativeHandler()
+ {
+ return new Function<CqlResult, Integer>()
+ {
+
+ @Override
+ public Integer apply(CqlResult result)
+ {
+ switch (result.getType())
+ {
+ case ROWS:
+ return result.getRows().size();
+ default:
+ return 1;
+ }
+ }
+ };
+ }
+
+ }
+
+ // Processes results from each client into an array of all key bytes returned
+ protected static final class RowsHandler implements ResultHandler<ByteBuffer[][]>
+ {
+ static final RowsHandler INSTANCE = new RowsHandler();
+
+ @Override
+ public Function<ResultSet, ByteBuffer[][]> javaDriverHandler()
+ {
+ return new Function<ResultSet, ByteBuffer[][]>()
+ {
+
+ @Override
+ public ByteBuffer[][] apply(ResultSet result)
+ {
+ if (result == null)
+ return new ByteBuffer[0][];
+ List<Row> rows = result.all();
+
+ ByteBuffer[][] r = new ByteBuffer[rows.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ {
+ Row row = rows.get(i);
+ r[i] = new ByteBuffer[row.getColumnDefinitions().size()];
+ for (int j = 0 ; j < row.getColumnDefinitions().size() ; j++)
+ r[i][j] = row.getBytes(j);
+ }
+ return r;
+ }
+ };
+ }
+
+ @Override
+ public Function<ResultMessage, ByteBuffer[][]> thriftHandler()
+ {
+ return new Function<ResultMessage, ByteBuffer[][]>()
+ {
+
+ @Override
+ public ByteBuffer[][] apply(ResultMessage result)
+ {
+ if (!(result instanceof ResultMessage.Rows))
+ return new ByteBuffer[0][];
+
+ ResultMessage.Rows rows = ((ResultMessage.Rows) result);
+ ByteBuffer[][] r = new ByteBuffer[rows.result.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ {
+ List<ByteBuffer> row = rows.result.rows.get(i);
+ r[i] = new ByteBuffer[row.size()];
+ for (int j = 0 ; j < row.size() ; j++)
+ r[i][j] = row.get(j);
+ }
+ return r;
+ }
+ };
+ }
+
+ @Override
+ public Function<CqlResult, ByteBuffer[][]> simpleNativeHandler()
+ {
+ return new Function<CqlResult, ByteBuffer[][]>()
+ {
+
+ @Override
+ public ByteBuffer[][] apply(CqlResult result)
+ {
+ ByteBuffer[][] r = new ByteBuffer[result.getRows().size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ {
+ CqlRow row = result.getRows().get(i);
+ r[i] = new ByteBuffer[row.getColumns().size()];
+ for (int j = 0 ; j < r[i].length ; j++)
+ r[i][j] = ByteBuffer.wrap(row.getColumns().get(j).getValue());
+ }
+ return r;
+ }
+ };
+ }
+
+ }
+ // Processes results from each client into an array of all key bytes returned
+ protected static final class KeysHandler implements ResultHandler<byte[][]>
+ {
+ static final KeysHandler INSTANCE = new KeysHandler();
+
+ @Override
+ public Function<ResultSet, byte[][]> javaDriverHandler()
+ {
+ return new Function<ResultSet, byte[][]>()
+ {
+
+ @Override
+ public byte[][] apply(ResultSet result)
+ {
+
+ if (result == null)
+ return new byte[0][];
+ List<Row> rows = result.all();
+ byte[][] r = new byte[rows.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ r[i] = rows.get(i).getBytes(0).array();
+ return r;
+ }
+ };
+ }
+
+ @Override
+ public Function<ResultMessage, byte[][]> thriftHandler()
+ {
+ return new Function<ResultMessage, byte[][]>()
+ {
+
+ @Override
+ public byte[][] apply(ResultMessage result)
+ {
+ if (result instanceof ResultMessage.Rows)
+ {
+ ResultMessage.Rows rows = ((ResultMessage.Rows) result);
+ byte[][] r = new byte[rows.result.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ r[i] = rows.result.rows.get(i).get(0).array();
+ return r;
+ }
+ return null;
+ }
+ };
+ }
+
+ @Override
+ public Function<CqlResult, byte[][]> simpleNativeHandler()
+ {
+ return new Function<CqlResult, byte[][]>()
+ {
+
+ @Override
+ public byte[][] apply(CqlResult result)
+ {
+ byte[][] r = new byte[result.getRows().size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ r[i] = result.getRows().get(i).getKey();
+ return r;
+ }
+ };
+ }
+
+ }
+
+ private static String getUnQuotedCqlBlob(ByteBuffer term, boolean isCQL3)
+ {
+ return isCQL3
+ ? "0x" + ByteBufferUtil.bytesToHex(term)
+ : ByteBufferUtil.bytesToHex(term);
+ }
+
+ /**
+ * Constructs a CQL query string by replacing instances of the character
+ * '?', with the corresponding parameter.
+ *
+ * @param query base query string to format
+ * @param parms sequence of string query parameters
+ * @return formatted CQL query string
+ */
+ private static String formatCqlQuery(String query, List<Object> parms, boolean isCql3)
+ {
+ int marker, position = 0;
+ StringBuilder result = new StringBuilder();
+
+ if (-1 == (marker = query.indexOf('?')) || parms.size() == 0)
+ return query;
+
+ for (Object parm : parms)
+ {
+ result.append(query.substring(position, marker));
+ 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)))
+ break;
+ }
+
+ if (position < query.length())
+ result.append(query.substring(position));
+
+ return result.toString();
+ }
+
+ private static List<ByteBuffer> toByteBufferParams(List<Object> params)
+ {
+ List<ByteBuffer> 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 settings.mode.cqlVersion == CqlVersion.CQL3
+ ? "\"" + string + "\""
+ : string;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
new file mode 100644
index 0000000..3a7f75a
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
@@ -0,0 +1,87 @@
+package org.apache.cassandra.stress.operations.predefined;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public class CqlReader extends CqlOperation<ByteBuffer[][]>
+{
+
+ public CqlReader(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.READ, timer, generator, settings);
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ StringBuilder query = new StringBuilder("SELECT ");
+
+ if (settings.columns.slice)
+ {
+ if (isCql2())
+ query.append("FIRST ").append(settings.columns.maxColumnsPerKey).append(" ''..''");
+ else
+ query.append("*");
+ }
+ else
+ {
+ for (int i = 0; i < settings.columns.maxColumnsPerKey ; i++)
+ {
+ if (i > 0)
+ query.append(",");
+ query.append(wrapInQuotesIfRequired(settings.columns.namestrs.get(i)));
+ }
+ }
+
+ query.append(" FROM ").append(wrapInQuotesIfRequired(type.table));
+
+ if (isCql2())
+ query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
+ query.append(" WHERE KEY=?");
+ return query.toString();
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ return Collections.<Object>singletonList(ByteBuffer.wrap(key));
+ }
+
+ @Override
+ protected CqlRunOp<ByteBuffer[][]> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ List<ByteBuffer> expectRow = getColumnValues();
+ return new CqlRunOpMatchResults(client, query, queryId, params, key, Arrays.asList(expectRow));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
new file mode 100644
index 0000000..7f6412b
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
@@ -0,0 +1,248 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+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.Operation;
+import org.apache.cassandra.stress.StressMetrics;
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.DistributionFixed;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.Row;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.CqlVersion;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.ColumnParent;
+import org.apache.cassandra.thrift.SlicePredicate;
+import org.apache.cassandra.thrift.SliceRange;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public abstract class PredefinedOperation extends Operation
+{
+ public final Command type;
+ private final Distribution columnCount;
+ private Object cqlCache;
+
+ public PredefinedOperation(Command type, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(timer, generator, settings, new DistributionFixed(1));
+ this.type = type;
+ this.columnCount = settings.columns.countDistribution.get();
+ }
+
+ public boolean isCql3()
+ {
+ return settings.mode.cqlVersion == CqlVersion.CQL3;
+ }
+ public boolean isCql2()
+ {
+ return settings.mode.cqlVersion == CqlVersion.CQL2;
+ }
+ public Object getCqlCache()
+ {
+ return cqlCache;
+ }
+ public void storeCqlCache(Object val)
+ {
+ cqlCache = val;
+ }
+
+ protected ByteBuffer getKey()
+ {
+ return (ByteBuffer) partitions.get(0).getPartitionKey(0);
+ }
+
+ final class ColumnSelection
+ {
+ final int[] indices;
+ final int lb, ub;
+ private ColumnSelection(int[] indices, int lb, int ub)
+ {
+ this.indices = indices;
+ this.lb = lb;
+ this.ub = ub;
+ }
+
+ public <V> List<V> select(List<V> in)
+ {
+ List<V> out = new ArrayList<>();
+ if (indices != null)
+ {
+ for (int i : indices)
+ out.add(in.get(i));
+ }
+ else
+ {
+ out.addAll(in.subList(lb, ub));
+ }
+ return out;
+ }
+
+ int count()
+ {
+ return indices != null ? indices.length : ub - lb;
+ }
+
+ SlicePredicate predicate()
+ {
+ final SlicePredicate predicate = new SlicePredicate();
+ if (indices == null)
+ {
+ predicate.setSlice_range(new SliceRange()
+ .setStart(settings.columns.names.get(lb))
+ .setFinish(new byte[] {})
+ .setReversed(false)
+ .setCount(count())
+ );
+ }
+ else
+ predicate.setColumn_names(select(settings.columns.names));
+ return predicate;
+
+ }
+ }
+
+ public String toString()
+ {
+ return type.toString();
+ }
+
+ ColumnSelection select()
+ {
+ if (settings.columns.slice)
+ {
+ int count = (int) columnCount.next();
+ int start;
+ if (count == settings.columns.maxColumnsPerKey)
+ start = 0;
+ else
+ start = 1 + ThreadLocalRandom.current().nextInt(settings.columns.maxColumnsPerKey - count);
+ return new ColumnSelection(null, start, start + count);
+ }
+
+ int count = (int) columnCount.next();
+ int totalCount = settings.columns.names.size();
+ if (count == settings.columns.names.size())
+ return new ColumnSelection(null, 0, count);
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ int[] indices = new int[count];
+ int c = 0, o = 0;
+ while (c < count && count + o < totalCount)
+ {
+ int leeway = totalCount - (count + o);
+ int spreadover = count - c;
+ o += Math.round(rnd.nextDouble() * (leeway / (double) spreadover));
+ indices[c] = o + c;
+ c++;
+ }
+ while (c < count)
+ {
+ indices[c] = o + c;
+ c++;
+ }
+ return new ColumnSelection(indices, 0, 0);
+ }
+
+ protected List<ByteBuffer> getColumnValues()
+ {
+ return getColumnValues(new ColumnSelection(null, 0, settings.columns.names.size()));
+ }
+
+ protected List<ByteBuffer> getColumnValues(ColumnSelection columns)
+ {
+ Row row = partitions.get(0).iterator(1).batch(1f).iterator().next();
+ ByteBuffer[] r = new ByteBuffer[columns.count()];
+ int c = 0;
+ if (columns.indices != null)
+ for (int i : columns.indices)
+ r[c++] = (ByteBuffer) row.get(i);
+ else
+ for (int i = columns.lb ; i < columns.ub ; i++)
+ r[c++] = (ByteBuffer) row.get(i);
+ return Arrays.asList(r);
+ }
+
+ public static Operation operation(Command type, Timer timer, PartitionGenerator generator, StressSettings settings, DistributionFactory counteradd)
+ {
+ switch (type)
+ {
+ case READ:
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftReader(timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlReader(timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+
+ case COUNTER_READ:
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftCounterGetter(timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlCounterGetter(timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ case WRITE:
+
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftInserter(timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlInserter(timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ case COUNTER_WRITE:
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftCounterAdder(counteradd, timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlCounterAdder(counteradd, timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ throw new UnsupportedOperationException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterAdder.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterAdder.java
new file mode 100644
index 0000000..ee766c3
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterAdder.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.*;
+
+public class ThriftCounterAdder extends PredefinedOperation
+{
+
+ final Distribution counteradd;
+ public ThriftCounterAdder(DistributionFactory counteradd, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_WRITE, timer, generator, settings);
+ this.counteradd = counteradd.get();
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ List<CounterColumn> columns = new ArrayList<>();
+ for (ByteBuffer name : select().select(settings.columns.names))
+ columns.add(new CounterColumn(name, counteradd.next()));
+
+ List<Mutation> mutations = new ArrayList<>(columns.size());
+ for (CounterColumn c : columns)
+ {
+ ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setCounter_column(c);
+ mutations.add(new Mutation().setColumn_or_supercolumn(cosc));
+ }
+ Map<String, List<Mutation>> row = Collections.singletonMap(type.table, mutations);
+
+ final ByteBuffer key = getKey();
+ final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
+
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ client.batch_mutate(record, settings.command.consistencyLevel);
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterGetter.java
new file mode 100644
index 0000000..10c6aab
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftCounterGetter.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+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.SlicePredicate;
+
+public class ThriftCounterGetter extends PredefinedOperation
+{
+ public ThriftCounterGetter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_READ, timer, generator, settings);
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ final SlicePredicate predicate = select().predicate();
+ final ByteBuffer key = getKey();
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ List<?> r = client.get_slice(key, new ColumnParent(type.table), predicate, settings.command.consistencyLevel);
+ return r != null && r.size() > 0;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
new file mode 100644
index 0000000..5c2acfe
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cassandra.db.marshal.TimeUUIDType;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.*;
+import org.apache.cassandra.utils.FBUtilities;
+import org.apache.cassandra.utils.UUIDGen;
+
+public final class ThriftInserter extends PredefinedOperation
+{
+
+ public ThriftInserter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.WRITE, timer, generator, settings);
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ final ByteBuffer key = getKey();
+ final List<Column> columns = getColumns();
+
+ List<Mutation> mutations = new ArrayList<>(columns.size());
+ for (Column c : columns)
+ {
+ ColumnOrSuperColumn column = new ColumnOrSuperColumn().setColumn(c);
+ mutations.add(new Mutation().setColumn_or_supercolumn(column));
+ }
+ Map<String, List<Mutation>> row = Collections.singletonMap(type.table, mutations);
+
+ final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
+
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ client.batch_mutate(record, settings.command.consistencyLevel);
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+ protected List<Column> getColumns()
+ {
+ final ColumnSelection selection = select();
+ final List<ByteBuffer> values = getColumnValues(selection);
+ final List<Column> columns = new ArrayList<>(values.size());
+ final List<ByteBuffer> names = select().select(settings.columns.names);
+ for (int i = 0 ; i < values.size() ; i++)
+ columns.add(new Column(names.get(i))
+ .setValue(values.get(i))
+ .setTimestamp(FBUtilities.timestampMicros()));
+ return columns;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftReader.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftReader.java
new file mode 100644
index 0000000..276d8c5
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftReader.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.stress.operations.predefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.Command;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.ColumnOrSuperColumn;
+import org.apache.cassandra.thrift.ColumnParent;
+import org.apache.cassandra.thrift.SlicePredicate;
+import org.apache.cassandra.thrift.SuperColumn;
+
+public final class ThriftReader extends PredefinedOperation
+{
+
+ public ThriftReader(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.READ, timer, generator, settings);
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ final ColumnSelection select = select();
+ final ByteBuffer key = getKey();
+ final List<ByteBuffer> expect = getColumnValues(select);
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ List<ColumnOrSuperColumn> row = client.get_slice(key, new ColumnParent(type.table), select.predicate(), settings.command.consistencyLevel);
+ if (expect == null)
+ return !row.isEmpty();
+ if (row == null)
+ return false;
+ if (row.size() != expect.size())
+ return false;
+ for (int i = 0 ; i < row.size() ; i++)
+ if (!row.get(i).getColumn().bufferForValue().equals(expect.get(i)))
+ return false;
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaInsert.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaInsert.java b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaInsert.java
new file mode 100644
index 0000000..7c5efac
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaInsert.java
@@ -0,0 +1,144 @@
+package org.apache.cassandra.stress.operations.userdefined;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.datastax.driver.core.BatchStatement;
+import com.datastax.driver.core.BoundStatement;
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.Statement;
+import org.apache.cassandra.db.ConsistencyLevel;
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.Partition;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.RatioDistribution;
+import org.apache.cassandra.stress.generate.Row;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.settings.ValidationType;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+
+public class SchemaInsert extends SchemaStatement
+{
+
+ private final BatchStatement.Type batchType;
+ private final RatioDistribution perVisit;
+ private final RatioDistribution perBatch;
+
+ public SchemaInsert(Timer timer, PartitionGenerator generator, StressSettings settings, Distribution partitionCount, RatioDistribution perVisit, RatioDistribution perBatch, Integer thriftId, PreparedStatement statement, ConsistencyLevel cl, BatchStatement.Type batchType)
+ {
+ super(timer, generator, settings, partitionCount, statement, thriftId, cl, ValidationType.NOT_FAIL);
+ this.batchType = batchType;
+ this.perVisit = perVisit;
+ this.perBatch = perBatch;
+ }
+
+ private class JavaDriverRun extends Runner
+ {
+ final JavaDriverClient client;
+
+ private JavaDriverRun(JavaDriverClient client)
+ {
+ this.client = client;
+ }
+
+ public boolean run() throws Exception
+ {
+ Partition.RowIterator[] iterators = new Partition.RowIterator[partitions.size()];
+ for (int i = 0 ; i < iterators.length ; i++)
+ iterators[i] = partitions.get(i).iterator(perVisit.next());
+ List<BoundStatement> stmts = new ArrayList<>();
+ partitionCount = partitions.size();
+
+ boolean done;
+ do
+ {
+ done = true;
+ stmts.clear();
+ for (Partition.RowIterator iterator : iterators)
+ {
+ if (iterator.done())
+ continue;
+
+ for (Row row : iterator.batch(perBatch.next()))
+ stmts.add(bindRow(row));
+
+ done &= iterator.done();
+ }
+
+ rowCount += stmts.size();
+
+ Statement stmt;
+ if (stmts.size() == 1)
+ {
+ stmt = stmts.get(0);
+ }
+ else
+ {
+ BatchStatement batch = new BatchStatement(batchType);
+ batch.setConsistencyLevel(JavaDriverClient.from(cl));
+ batch.addAll(stmts);
+ stmt = batch;
+ }
+ validate(client.getSession().execute(stmt));
+
+ } while (!done);
+
+ return true;
+ }
+ }
+
+ private class ThriftRun extends Runner
+ {
+ final ThriftClient client;
+
+ private ThriftRun(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ public boolean run() throws Exception
+ {
+ Partition.RowIterator[] iterators = new Partition.RowIterator[partitions.size()];
+ for (int i = 0 ; i < iterators.length ; i++)
+ iterators[i] = partitions.get(i).iterator(perVisit.next());
+ partitionCount = partitions.size();
+
+ boolean done;
+ do
+ {
+ done = true;
+ for (Partition.RowIterator iterator : iterators)
+ {
+ if (iterator.done())
+ continue;
+
+ for (Row row : iterator.batch(perBatch.next()))
+ {
+ validate(client.execute_prepared_cql3_query(thriftId, iterator.partition().getToken(), thriftRowArgs(row), settings.command.consistencyLevel));
+ rowCount += 1;
+ }
+
+ done &= iterator.done();
+ }
+ } while (!done);
+
+ return true;
+ }
+ }
+
+ @Override
+ public void run(JavaDriverClient client) throws IOException
+ {
+ timeWithRetry(new JavaDriverRun(client));
+ }
+
+ @Override
+ public void run(ThriftClient client) throws IOException
+ {
+ timeWithRetry(new ThriftRun(client));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaQuery.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaQuery.java b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaQuery.java
new file mode 100644
index 0000000..9cec39b
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaQuery.java
@@ -0,0 +1,86 @@
+package org.apache.cassandra.stress.operations.userdefined;
+
+import java.io.IOException;
+
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.ResultSet;
+import org.apache.cassandra.db.ConsistencyLevel;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.settings.OptionDistribution;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.settings.ValidationType;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.CqlResult;
+import org.apache.cassandra.thrift.ThriftConversion;
+
+public class SchemaQuery extends SchemaStatement
+{
+
+ public SchemaQuery(Timer timer, PartitionGenerator generator, StressSettings settings, Integer thriftId, PreparedStatement statement, ConsistencyLevel cl, ValidationType validationType)
+ {
+ super(timer, generator, settings, OptionDistribution.get("fixed(1)").get(), statement, thriftId, cl, validationType);
+ }
+
+ int execute(JavaDriverClient client) throws Exception
+ {
+ return client.getSession().execute(bindRandom(partitions.get(0))).all().size();
+ }
+
+ int execute(ThriftClient client) throws Exception
+ {
+ return client.execute_prepared_cql3_query(thriftId, partitions.get(0).getToken(), thriftRandomArgs(partitions.get(0)), ThriftConversion.toThrift(cl)).getRowsSize();
+ }
+
+ private class JavaDriverRun extends Runner
+ {
+ final JavaDriverClient client;
+
+ private JavaDriverRun(JavaDriverClient client)
+ {
+ this.client = client;
+ }
+
+ public boolean run() throws Exception
+ {
+ ResultSet rs = client.getSession().execute(bindRandom(partitions.get(0)));
+ validate(rs);
+ rowCount = rs.all().size();
+ partitionCount = Math.min(1, rowCount);
+ return true;
+ }
+ }
+
+ private class ThriftRun extends Runner
+ {
+ final ThriftClient client;
+
+ private ThriftRun(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ public boolean run() throws Exception
+ {
+ CqlResult rs = client.execute_prepared_cql3_query(thriftId, partitions.get(0).getToken(), thriftRandomArgs(partitions.get(0)), ThriftConversion.toThrift(cl));
+ validate(rs);
+ rowCount = rs.getRowsSize();
+ partitionCount = Math.min(1, rowCount);
+ return true;
+ }
+ }
+
+ @Override
+ public void run(JavaDriverClient client) throws IOException
+ {
+ timeWithRetry(new JavaDriverRun(client));
+ }
+
+ @Override
+ public void run(ThriftClient client) throws IOException
+ {
+ timeWithRetry(new ThriftRun(client));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaStatement.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaStatement.java b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaStatement.java
new file mode 100644
index 0000000..aac40c5
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/SchemaStatement.java
@@ -0,0 +1,164 @@
+package org.apache.cassandra.stress.operations.userdefined;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import com.datastax.driver.core.BoundStatement;
+import com.datastax.driver.core.ColumnDefinitions;
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.ResultSet;
+import org.apache.cassandra.db.ConsistencyLevel;
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.Partition;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.Row;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.settings.ValidationType;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.CqlResult;
+import org.apache.cassandra.transport.SimpleClient;
+
+public abstract class SchemaStatement extends Operation
+{
+
+ final PartitionGenerator generator;
+ private final PreparedStatement statement;
+ final Integer thriftId;
+ final ConsistencyLevel cl;
+ final ValidationType validationType;
+ private final int[] argumentIndex;
+ private final Object[] bindBuffer;
+ private final Object[][] randomBuffer;
+ private final Random random = new Random();
+
+ public SchemaStatement(Timer timer, PartitionGenerator generator, StressSettings settings, Distribution partitionCount,
+ PreparedStatement statement, Integer thriftId, ConsistencyLevel cl, ValidationType validationType)
+ {
+ super(timer, generator, settings, partitionCount);
+ this.generator = generator;
+ this.statement = statement;
+ this.thriftId = thriftId;
+ this.cl = cl;
+ this.validationType = validationType;
+ argumentIndex = new int[statement.getVariables().size()];
+ bindBuffer = new Object[argumentIndex.length];
+ randomBuffer = new Object[argumentIndex.length][argumentIndex.length];
+ int i = 0;
+ for (ColumnDefinitions.Definition definition : statement.getVariables())
+ argumentIndex[i++] = generator.indexOf(definition.getName());
+ }
+
+ private int filLRandom(Partition partition)
+ {
+ int c = 0;
+ for (Row row : partition.iterator(randomBuffer.length).batch(1f))
+ {
+ Object[] randomRow = randomBuffer[c++];
+ for (int i = 0 ; i < argumentIndex.length ; i++)
+ randomRow[i] = row.get(argumentIndex[i]);
+ if (c >= randomBuffer.length)
+ break;
+ }
+ return c;
+ }
+
+ BoundStatement bindRandom(Partition partition)
+ {
+ int c = filLRandom(partition);
+ for (int i = 0 ; i < argumentIndex.length ; i++)
+ {
+ int argIndex = argumentIndex[i];
+ bindBuffer[i] = randomBuffer[argIndex < 0 ? 0 : random.nextInt(c)][i];
+ }
+ return statement.bind(bindBuffer);
+ }
+
+ BoundStatement bindRow(Row row)
+ {
+ for (int i = 0 ; i < argumentIndex.length ; i++)
+ bindBuffer[i] = row.get(argumentIndex[i]);
+ return statement.bind(bindBuffer);
+ }
+
+ List<ByteBuffer> thriftRowArgs(Row row)
+ {
+ List<ByteBuffer> args = new ArrayList<>();
+ for (int i : argumentIndex)
+ args.add(generator.convert(i, row.get(i)));
+ return args;
+ }
+
+ List<ByteBuffer> thriftRandomArgs(Partition partition)
+ {
+ List<ByteBuffer> args = new ArrayList<>();
+ int c = filLRandom(partition);
+ for (int i = 0 ; i < argumentIndex.length ; i++)
+ {
+ int argIndex = argumentIndex[i];
+ args.add(generator.convert(argIndex, randomBuffer[argIndex < 0 ? 0 : random.nextInt(c)][i]));
+ }
+ return args;
+ }
+
+ void validate(ResultSet rs)
+ {
+ switch (validationType)
+ {
+ case NOT_FAIL:
+ return;
+ case NON_ZERO:
+ if (rs.all().size() == 0)
+ throw new IllegalStateException("Expected non-zero results");
+ break;
+ default:
+ throw new IllegalStateException("Unsupported validation type");
+ }
+ }
+
+ void validate(CqlResult rs)
+ {
+ switch (validationType)
+ {
+ case NOT_FAIL:
+ return;
+ case NON_ZERO:
+ if (rs.getRowsSize() == 0)
+ throw new IllegalStateException("Expected non-zero results");
+ break;
+ default:
+ throw new IllegalStateException("Unsupported validation type");
+ }
+ }
+
+ @Override
+ public void run(SimpleClient client) throws IOException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ abstract class Runner implements RunOp
+ {
+ int partitionCount;
+ int rowCount;
+
+ @Override
+ public int partitionCount()
+ {
+ return partitionCount;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return rowCount;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/Command.java
----------------------------------------------------------------------
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 ac10014..7138cbb 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/Command.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/Command.java
@@ -41,19 +41,6 @@ public enum Command
"Interleaving of any basic commands, with configurable ratio and distribution - the cluster must first be populated by a write test",
CommandCategory.MIXED
),
- RANGE_SLICE(false, "Standard1", "Super1",
- "Range slice queries - the cluster must first be populated by a write test",
- CommandCategory.MULTI
- ),
- INDEXED_RANGE_SLICE(false, "Standard1", "Super1",
- "Range slice queries through a secondary index. The cluster must first be populated by a write test, with indexing enabled.",
- CommandCategory.BASIC
- ),
- READ_MULTI(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
- ),
COUNTER_WRITE(true, "Counter1", "SuperCounter1",
"counter_add",
"Multiple concurrent updates of counters.",
@@ -64,6 +51,10 @@ public enum Command
"Multiple concurrent reads of counters. The cluster must first be populated by a counterwrite test.",
CommandCategory.BASIC
),
+ USER(true, null, null,
+ "Interleaving of user provided queries, with configurable ratio and distribution",
+ CommandCategory.USER
+ ),
HELP(false, null, null, "-?", "Print help for a command or option", null),
PRINT(false, null, null, "Inspect the output of a distribution definition", null),
@@ -136,11 +127,12 @@ public enum Command
}
switch (category)
{
+ case USER:
+ return SettingsCommandUser.helpPrinter();
case BASIC:
- case MULTI:
- return SettingsCommand.helpPrinter(this);
+ return SettingsCommandPreDefined.helpPrinter(this);
case MIXED:
- return SettingsCommandMixed.helpPrinter();
+ return SettingsCommandPreDefinedMixed.helpPrinter();
}
throw new AssertionError();
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java b/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java
index 4372f59..e9dd946 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/CommandCategory.java
@@ -24,6 +24,6 @@ package org.apache.cassandra.stress.settings;
public enum CommandCategory
{
BASIC,
- MULTI,
- MIXED
+ MIXED,
+ USER
}
[13/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionOffsetApache.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionOffsetApache.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionOffsetApache.java
new file mode 100644
index 0000000..b0e41eb
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionOffsetApache.java
@@ -0,0 +1,80 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.commons.math3.distribution.AbstractRealDistribution;
+
+public class DistributionOffsetApache extends Distribution
+{
+
+ final AbstractRealDistribution delegate;
+ final long min, delta;
+
+ public DistributionOffsetApache(AbstractRealDistribution delegate, long min, long max)
+ {
+ this.delegate = delegate;
+ this.min = min;
+ this.delta = max - min;
+ }
+
+ public void setSeed(long seed)
+ {
+ delegate.reseedRandomGenerator(seed);
+ }
+
+ @Override
+ public long next()
+ {
+ return offset(min, delta, delegate.sample());
+ }
+
+ public double nextDouble()
+ {
+ return offsetDouble(min, delta, delegate.sample());
+ }
+
+ @Override
+ public long inverseCumProb(double cumProb)
+ {
+ return offset(min, delta, delegate.inverseCumulativeProbability(cumProb));
+ }
+
+ private long offset(long min, long delta, double val)
+ {
+ long r = (long) val;
+ if (r < 0)
+ r = 0;
+ if (r > delta)
+ r = delta;
+ return min + r;
+ }
+
+ private double offsetDouble(long min, long delta, double r)
+ {
+ if (r < 0)
+ r = 0;
+ if (r > delta)
+ r = delta;
+ return min + r;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/Partition.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/Partition.java b/tools/stress/src/org/apache/cassandra/stress/generate/Partition.java
new file mode 100644
index 0000000..856d550
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/Partition.java
@@ -0,0 +1,343 @@
+package org.apache.cassandra.stress.generate;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Queue;
+import java.util.Random;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.BytesType;
+import org.apache.cassandra.stress.generate.values.Generator;
+
+// a partition is re-used to reduce garbage generation, as is its internal RowIterator
+public class Partition
+{
+
+ private long idseed;
+ private final Object[] partitionKey;
+ private final PartitionGenerator generator;
+ private final RowIterator iterator;
+
+ public Partition(PartitionGenerator generator)
+ {
+ this.generator = generator;
+ this.partitionKey = new Object[generator.partitionKey.size()];
+ if (generator.clusteringComponents.size() > 0)
+ iterator = new MultiRowIterator();
+ else
+ iterator = new SingleRowIterator();
+ }
+
+ void setSeed(long seed)
+ {
+ long idseed = 0;
+ for (int i = 0 ; i < partitionKey.length ; i++)
+ {
+ Generator generator = this.generator.partitionKey.get(i);
+ // set the partition key seed based on the current work item we're processing
+ generator.setSeed(seed);
+ Object key = generator.generate();
+ partitionKey[i] = key;
+ // then contribute this value to the data seed
+ idseed = seed(key, generator.type, idseed);
+ }
+ this.idseed = idseed;
+ }
+
+ public RowIterator iterator(double useChance)
+ {
+ iterator.reset(useChance, 0);
+ return iterator;
+ }
+
+ public RowIterator iterator(int targetCount)
+ {
+ iterator.reset(Double.NaN, targetCount);
+ return iterator;
+ }
+
+ class SingleRowIterator extends RowIterator
+ {
+ boolean done;
+
+ void reset(double useChance, int targetCount)
+ {
+ done = false;
+ }
+
+ public Iterable<Row> batch(double ratio)
+ {
+ if (done)
+ return Collections.emptyList();
+ for (int i = 0 ; i < row.row.length ; i++)
+ {
+ Generator gen = generator.valueComponents.get(i);
+ gen.setSeed(idseed);
+ row.row[i] = gen.generate();
+ }
+ done = true;
+ return Collections.singleton(row);
+ }
+
+ public boolean done()
+ {
+ return done;
+ }
+ }
+
+ public abstract class RowIterator
+ {
+ // we reuse the row object to save garbage
+ final Row row = new Row(partitionKey, new Object[generator.clusteringComponents.size() + generator.valueComponents.size()]);
+
+ public abstract Iterable<Row> batch(double ratio);
+ abstract void reset(double useChance, int targetCount);
+
+ public abstract boolean done();
+
+ public Partition partition()
+ {
+ return Partition.this;
+ }
+ }
+
+ // permits iterating a random subset of the procedurally generated rows in this partition; this is the only mechanism for visiting rows
+ // we maintain a stack of clustering components and their seeds; for each clustering component we visit, we generate all values it takes at that level,
+ // and then, using the average (total) number of children it takes we randomly choose whether or not we visit its children;
+ // if we do, we generate all possible values the children can take, and repeat the process. So at any one time we are using space proportional
+ // to C.N, where N is the average number of values each clustering component takes, as opposed to N^C total values in the partition.
+ class MultiRowIterator extends RowIterator
+ {
+
+ // probability any single row will be generated in this iteration
+ double useChance;
+ double expectedRowCount;
+
+ // the current seed in use at any given level; used to save recalculating it for each row, so we only need to recalc
+ // from prior row
+ final long[] clusteringSeeds = new long[generator.clusteringComponents.size()];
+ // the components remaining to be visited for each level of the current stack
+ final Queue<Object>[] clusteringComponents = new ArrayDeque[generator.clusteringComponents.size()];
+
+ // we want our chance of selection to be applied uniformly, so we compound the roll we make at each level
+ // so that we know with what chance we reached there, and we adjust our roll at that level by that amount
+ double[] chancemodifier = new double[generator.clusteringComponents.size()];
+ double[] rollmodifier = new double[generator.clusteringComponents.size()];
+
+ // reusable set for generating unique clustering components
+ final Set<Object> unique = new HashSet<>();
+ final Random random = new Random();
+
+ MultiRowIterator()
+ {
+ for (int i = 0 ; i < clusteringComponents.length ; i++)
+ clusteringComponents[i] = new ArrayDeque<>();
+ rollmodifier[0] = 1f;
+ chancemodifier[0] = generator.clusteringChildAverages[0];
+ }
+
+ void reset(double useChance, int targetCount)
+ {
+ generator.clusteringComponents.get(0).setSeed(idseed);
+ int firstComponentCount = (int) generator.clusteringComponents.get(0).clusteringDistribution.next();
+ this.expectedRowCount = firstComponentCount * generator.clusteringChildAverages[0];
+ if (Double.isNaN(useChance))
+ useChance = Math.max(0d, Math.min(1d, targetCount / expectedRowCount));
+
+ for (Queue<?> q : clusteringComponents)
+ q.clear();
+
+ this.useChance = useChance;
+ clusteringSeeds[0] = idseed;
+ clusteringComponents[0].add(this);
+ fill(clusteringComponents[0], firstComponentCount, generator.clusteringComponents.get(0));
+ advance(0, 1f);
+ }
+
+ void fill(int component)
+ {
+ long seed = clusteringSeeds[component - 1];
+ Generator gen = generator.clusteringComponents.get(component);
+ gen.setSeed(seed);
+ clusteringSeeds[component] = seed(clusteringComponents[component - 1].peek(), generator.clusteringComponents.get(component - 1).type, seed);
+ fill(clusteringComponents[component], (int) gen.clusteringDistribution.next(), gen);
+ }
+
+ void fill(Queue<Object> queue, int count, Generator generator)
+ {
+ if (count == 1)
+ {
+ queue.add(generator.generate());
+ }
+ else
+ {
+ unique.clear();
+ for (int i = 0 ; i < count ; i++)
+ {
+ Object next = generator.generate();
+ if (unique.add(next))
+ queue.add(next);
+ }
+ }
+ }
+
+ private boolean advance(double continueChance)
+ {
+ // we always start at the leaf level
+ int depth = clusteringComponents.length - 1;
+ // fill the row with the position we *were* at (unless pre-start)
+ for (int i = clusteringSeeds.length ; i < row.row.length ; i++)
+ {
+ Generator gen = generator.valueComponents.get(i - clusteringSeeds.length);
+ long seed = clusteringSeeds[depth];
+ seed = seed(clusteringComponents[depth].peek(), generator.clusteringComponents.get(depth).type, seed);
+ gen.setSeed(seed);
+ row.row[i] = gen.generate();
+ }
+ clusteringComponents[depth].poll();
+
+ return advance(depth, continueChance);
+ }
+
+ private boolean advance(int depth, double continueChance)
+ {
+ // advance the leaf component
+ clusteringComponents[depth].poll();
+ while (true)
+ {
+ if (clusteringComponents[depth].isEmpty())
+ {
+ if (depth == 0)
+ return false;
+ depth--;
+ clusteringComponents[depth].poll();
+ continue;
+ }
+
+ // the chance of descending is the uniform use chance, multiplied by the number of children
+ // we would on average generate (so if we have a 0.1 use chance, but should generate 10 children
+ // then we will always descend), multiplied by 1/(compound roll), where (compound roll) is the
+ // chance with which we reached this depth, i.e. if we already beat 50/50 odds, we double our
+ // chance of beating this next roll
+ double thischance = useChance * chancemodifier[depth];
+ if (thischance > 0.999f || thischance >= random.nextDouble())
+ {
+ row.row[depth] = clusteringComponents[depth].peek();
+ depth++;
+ if (depth == clusteringComponents.length)
+ break;
+ rollmodifier[depth] = rollmodifier[depth - 1] / Math.min(1d, thischance);
+ chancemodifier[depth] = generator.clusteringChildAverages[depth] * rollmodifier[depth];
+ fill(depth);
+ continue;
+ }
+
+ clusteringComponents[depth].poll();
+ }
+
+ return continueChance >= 1.0d || continueChance >= random.nextDouble();
+ }
+
+ public Iterable<Row> batch(final double ratio)
+ {
+ final double continueChance = 1d - (Math.pow(ratio, expectedRowCount * useChance));
+ return new Iterable<Row>()
+ {
+ public Iterator<Row> iterator()
+ {
+ return new Iterator<Row>()
+ {
+ boolean hasNext = true;
+ public boolean hasNext()
+ {
+ return hasNext;
+ }
+
+ public Row next()
+ {
+ hasNext = advance(continueChance);
+ return row;
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ }
+
+ public boolean done()
+ {
+ return clusteringComponents[0].isEmpty();
+ }
+
+ public Partition partition()
+ {
+ return Partition.this;
+ }
+ }
+
+ public String getKeyAsString()
+ {
+ StringBuilder sb = new StringBuilder();
+ int i = 0;
+ for (Object key : partitionKey)
+ {
+ if (i > 0)
+ sb.append("|");
+ AbstractType type = generator.partitionKey.get(i++).type;
+ sb.append(type.getString(type.decompose(key)));
+ }
+ return sb.toString();
+ }
+
+ static long seed(Object object, AbstractType type, long seed)
+ {
+ if (object instanceof ByteBuffer)
+ {
+ ByteBuffer buf = (ByteBuffer) object;
+ for (int i = buf.position() ; i < buf.limit() ; i++)
+ seed = (31 * seed) + buf.get(i);
+ return seed;
+ }
+ else if (object instanceof String)
+ {
+ String str = (String) object;
+ for (int i = 0 ; i < str.length() ; i++)
+ seed = (31 * seed) + str.charAt(i);
+ return seed;
+ }
+ else if (object instanceof Number)
+ {
+ return (seed * 31) + ((Number) object).longValue();
+ }
+ else if (object instanceof UUID)
+ {
+ return seed * 31 + (((UUID) object).getLeastSignificantBits() ^ ((UUID) object).getMostSignificantBits());
+ }
+ else
+ {
+ return seed(type.decompose(object), BytesType.instance, seed);
+ }
+ }
+
+ public Object getPartitionKey(int i)
+ {
+ return partitionKey[i];
+ }
+
+ // used for thrift smart routing - if it's a multi-part key we don't try to route correctly right now
+ public ByteBuffer getToken()
+ {
+ return generator.partitionKey.get(0).type.decompose(partitionKey[0]);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/PartitionGenerator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/PartitionGenerator.java b/tools/stress/src/org/apache/cassandra/stress/generate/PartitionGenerator.java
new file mode 100644
index 0000000..78002fb
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/PartitionGenerator.java
@@ -0,0 +1,80 @@
+package org.apache.cassandra.stress.generate;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import com.google.common.collect.Iterables;
+
+import org.apache.cassandra.stress.generate.values.Generator;
+
+public class PartitionGenerator
+{
+
+ public final double maxRowCount;
+ final List<Generator> partitionKey;
+ final List<Generator> clusteringComponents;
+ final List<Generator> valueComponents;
+ final int[] clusteringChildAverages;
+
+ private final Map<String, Integer> indexMap;
+
+ final List<Partition> recyclable = new ArrayList<>();
+ int partitionsInUse = 0;
+
+ public void reset()
+ {
+ partitionsInUse = 0;
+ }
+
+ public PartitionGenerator(List<Generator> partitionKey, List<Generator> clusteringComponents, List<Generator> valueComponents)
+ {
+ this.partitionKey = partitionKey;
+ this.clusteringComponents = clusteringComponents;
+ this.valueComponents = valueComponents;
+ this.clusteringChildAverages = new int[clusteringComponents.size()];
+ for (int i = clusteringChildAverages.length - 1 ; i >= 0 ; i--)
+ clusteringChildAverages[i] = (int) (i < (clusteringChildAverages.length - 1) ? clusteringComponents.get(i + 1).clusteringDistribution.average() * clusteringChildAverages[i + 1] : 1);
+ double maxRowCount = 1d;
+ for (Generator component : clusteringComponents)
+ maxRowCount *= component.clusteringDistribution.maxValue();
+ this.maxRowCount = maxRowCount;
+ this.indexMap = new HashMap<>();
+ int i = 0;
+ for (Generator generator : partitionKey)
+ indexMap.put(generator.name, --i);
+ i = 0;
+ for (Generator generator : Iterables.concat(clusteringComponents, valueComponents))
+ indexMap.put(generator.name, i++);
+ }
+
+ public int indexOf(String name)
+ {
+ Integer i = indexMap.get(name);
+ if (i == null)
+ throw new NoSuchElementException();
+ return i;
+ }
+
+ public Partition generate(long seed)
+ {
+ if (recyclable.size() <= partitionsInUse || recyclable.get(partitionsInUse) == null)
+ recyclable.add(new Partition(this));
+
+ Partition partition = recyclable.get(partitionsInUse++);
+ partition.setSeed(seed);
+ return partition;
+ }
+
+ public ByteBuffer convert(int c, Object v)
+ {
+ if (c < 0)
+ return partitionKey.get(-1-c).type.decompose(v);
+ if (c < clusteringComponents.size())
+ return clusteringComponents.get(c).type.decompose(v);
+ return valueComponents.get(c - clusteringComponents.size()).type.decompose(v);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistribution.java b/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistribution.java
new file mode 100644
index 0000000..fb5a373
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistribution.java
@@ -0,0 +1,25 @@
+package org.apache.cassandra.stress.generate;
+
+public class RatioDistribution
+{
+
+ final Distribution distribution;
+ final double divisor;
+
+ public RatioDistribution(Distribution distribution, double divisor)
+ {
+ this.distribution = distribution;
+ this.divisor = divisor;
+ }
+
+ // yields a value between 0 and 1
+ public double next()
+ {
+ return Math.max(0f, Math.min(1f, distribution.nextDouble() / divisor));
+ }
+
+ public double max()
+ {
+ return Math.min(1d, distribution.maxValue() / divisor);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistributionFactory.java
new file mode 100644
index 0000000..16474d8
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistributionFactory.java
@@ -0,0 +1,31 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.Serializable;
+
+public interface RatioDistributionFactory extends Serializable
+{
+
+ RatioDistribution get();
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/Row.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/Row.java b/tools/stress/src/org/apache/cassandra/stress/generate/Row.java
new file mode 100644
index 0000000..d3b9a2a
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/Row.java
@@ -0,0 +1,22 @@
+package org.apache.cassandra.stress.generate;
+
+public class Row
+{
+
+ final Object[] partitionKey;
+ final Object[] row;
+
+ public Row(Object[] partitionKey, Object[] row)
+ {
+ this.partitionKey = partitionKey;
+ this.row = row;
+ }
+
+ public Object get(int column)
+ {
+ if (column < 0)
+ return partitionKey[-1-column];
+ return row[column];
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/SeedGenerator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/SeedGenerator.java b/tools/stress/src/org/apache/cassandra/stress/generate/SeedGenerator.java
new file mode 100644
index 0000000..6c1bc7f
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/SeedGenerator.java
@@ -0,0 +1,8 @@
+package org.apache.cassandra.stress.generate;
+
+public interface SeedGenerator
+{
+
+ long next(long workIndex);
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/SeedRandomGenerator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/SeedRandomGenerator.java b/tools/stress/src/org/apache/cassandra/stress/generate/SeedRandomGenerator.java
new file mode 100644
index 0000000..bbaaeb8
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/SeedRandomGenerator.java
@@ -0,0 +1,33 @@
+package org.apache.cassandra.stress.generate;
+
+public class SeedRandomGenerator implements SeedGenerator
+{
+
+ final Distribution distribution;
+ final Distribution clustering;
+
+ private long next;
+ private int count;
+
+ public SeedRandomGenerator(Distribution distribution, Distribution clustering)
+ {
+ this.distribution = distribution;
+ this.clustering = clustering;
+ }
+
+ public long next(long workIndex)
+ {
+ if (count == 0)
+ {
+ next = distribution.next();
+ count = (int) clustering.next();
+ }
+ long result = next;
+ count--;
+ if (next == distribution.maxValue())
+ next = distribution.minValue();
+ else
+ next++;
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/SeedSeriesGenerator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/SeedSeriesGenerator.java b/tools/stress/src/org/apache/cassandra/stress/generate/SeedSeriesGenerator.java
new file mode 100644
index 0000000..27967d2
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/SeedSeriesGenerator.java
@@ -0,0 +1,21 @@
+package org.apache.cassandra.stress.generate;
+
+public class SeedSeriesGenerator implements SeedGenerator
+{
+
+ final long min;
+ final long count;
+
+ public SeedSeriesGenerator(long min, long max)
+ {
+ if (min > max)
+ throw new IllegalStateException();
+ this.min = min;
+ this.count = 1 + max - min;
+ }
+
+ public long next(long workIndex)
+ {
+ return min + (workIndex % count);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Booleans.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Booleans.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Booleans.java
new file mode 100644
index 0000000..b1d84d6
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Booleans.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.BooleanType;
+
+public class Booleans extends Generator<Boolean>
+{
+ public Booleans(String name, GeneratorConfig config)
+ {
+ super(BooleanType.instance, config, name);
+ }
+
+ @Override
+ public Boolean generate()
+ {
+ return identityDistribution.next() % 1 == 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Bytes.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Bytes.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Bytes.java
new file mode 100644
index 0000000..2a5bddf
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Bytes.java
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.BytesType;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
+
+public class Bytes extends Generator<ByteBuffer>
+{
+ private final byte[] bytes;
+ private final Random rand = new Random();
+
+ public Bytes(String name, GeneratorConfig config)
+ {
+ super(BytesType.instance, config, name);
+ bytes = new byte[(int) sizeDistribution.maxValue()];
+ }
+
+ @Override
+ public ByteBuffer generate()
+ {
+ long seed = identityDistribution.next();
+ sizeDistribution.setSeed(seed);
+ rand.setSeed(~seed);
+ int size = (int) sizeDistribution.next();
+ for (int i = 0; i < size; )
+ for (int v = rand.nextInt(),
+ n = Math.min(size - i, Integer.SIZE/Byte.SIZE);
+ n-- > 0; v >>= Byte.SIZE)
+ bytes[i++] = (byte)v;
+ return ByteBuffer.wrap(Arrays.copyOf(bytes, size));
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Dates.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Dates.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Dates.java
new file mode 100644
index 0000000..7d36be2
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Dates.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.util.Date;
+
+import org.apache.cassandra.db.marshal.DateType;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.settings.OptionDistribution;
+
+public class Dates extends Generator<Date>
+{
+ public Dates(String name, GeneratorConfig config)
+ {
+ super(DateType.instance, config, name);
+ }
+
+ @Override
+ public Date generate()
+ {
+ return new Date(identityDistribution.next());
+ }
+
+ DistributionFactory defaultIdentityDistribution()
+ {
+ return OptionDistribution.get("uniform(1.." + Long.toString(50L*365L*24L*60L*60L*1000L) + ")");
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Doubles.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Doubles.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Doubles.java
new file mode 100644
index 0000000..76e983d
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Doubles.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.DoubleType;
+
+public class Doubles extends Generator<Double>
+{
+ public Doubles(String name, GeneratorConfig config)
+ {
+ super(DoubleType.instance, config, name);
+ }
+
+ @Override
+ public Double generate()
+ {
+ return identityDistribution.nextDouble();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Floats.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Floats.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Floats.java
new file mode 100644
index 0000000..8e23c11
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Floats.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.FloatType;
+
+public class Floats extends Generator<Float>
+{
+ public Floats(String name, GeneratorConfig config)
+ {
+ super(FloatType.instance, config, name);
+ }
+
+ @Override
+ public Float generate()
+ {
+ return (float) identityDistribution.nextDouble();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Generator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Generator.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Generator.java
new file mode 100644
index 0000000..13343de
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Generator.java
@@ -0,0 +1,50 @@
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.settings.OptionDistribution;
+
+public abstract class Generator<T>
+{
+
+ public final String name;
+ public final AbstractType<T> type;
+ final long salt;
+ final Distribution identityDistribution;
+ final Distribution sizeDistribution;
+ public final Distribution clusteringDistribution;
+
+ public Generator(AbstractType<T> type, GeneratorConfig config, String name)
+ {
+ this.type = type;
+ this.name = name;
+ this.salt = config.salt;
+ this.identityDistribution = config.getIdentityDistribution(defaultIdentityDistribution());
+ this.sizeDistribution = config.getSizeDistribution(defaultSizeDistribution());
+ this.clusteringDistribution = config.getClusteringDistribution(defaultClusteringDistribution());
+ }
+
+ public void setSeed(long seed)
+ {
+ identityDistribution.setSeed(seed ^ salt);
+ clusteringDistribution.setSeed(seed ^ ~salt);
+ }
+
+ public abstract T generate();
+
+ DistributionFactory defaultIdentityDistribution()
+ {
+ return OptionDistribution.get("uniform(1..100B)");
+ }
+
+ DistributionFactory defaultSizeDistribution()
+ {
+ return OptionDistribution.get("uniform(4..8)");
+ }
+
+ DistributionFactory defaultClusteringDistribution()
+ {
+ return OptionDistribution.get("fixed(1)");
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/GeneratorConfig.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/GeneratorConfig.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/GeneratorConfig.java
new file mode 100644
index 0000000..8f7b2ea
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/GeneratorConfig.java
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.MurmurHash;
+
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.Map;
+
+public class GeneratorConfig implements Serializable
+{
+ public final long salt;
+
+ private final DistributionFactory clusteringDistributions;
+ private final DistributionFactory sizeDistributions;
+ private final DistributionFactory identityDistributions;
+
+ public GeneratorConfig(String seedStr, DistributionFactory clusteringDistributions, DistributionFactory sizeDistributions, DistributionFactory identityDistributions)
+ {
+ this.clusteringDistributions = clusteringDistributions;
+ this.sizeDistributions = sizeDistributions;
+ this.identityDistributions = identityDistributions;
+ ByteBuffer buf = ByteBufferUtil.bytes(seedStr);
+ long[] hash = new long[2];
+ MurmurHash.hash3_x64_128(buf, buf.position(), buf.remaining(), 0, hash);
+ salt = hash[0];
+ }
+
+ Distribution getClusteringDistribution(DistributionFactory deflt)
+ {
+ return (clusteringDistributions == null ? deflt : clusteringDistributions).get();
+ }
+
+ Distribution getIdentityDistribution(DistributionFactory deflt)
+ {
+ return (identityDistributions == null ? deflt : identityDistributions).get();
+ }
+
+ Distribution getSizeDistribution(DistributionFactory deflt)
+ {
+ return (sizeDistributions == null ? deflt : sizeDistributions).get();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/HexBytes.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/HexBytes.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/HexBytes.java
new file mode 100644
index 0000000..db46bac
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/HexBytes.java
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import org.apache.cassandra.db.marshal.BytesType;
+
+public class HexBytes extends Generator<ByteBuffer>
+{
+ private final byte[] bytes;
+
+ public HexBytes(String name, GeneratorConfig config)
+ {
+ super(BytesType.instance, config, name);
+ bytes = new byte[(int) sizeDistribution.maxValue()];
+ }
+
+ @Override
+ public ByteBuffer generate()
+ {
+ long seed = identityDistribution.next();
+ sizeDistribution.setSeed(seed);
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i +=16)
+ {
+ long value = identityDistribution.next();
+ for (int j = 0 ; j < 16 && i + j < size ; j++)
+ {
+ int v = (int) (value & 15);
+ bytes[i + j] = (byte) ((v < 10 ? '0' : 'A') + v);
+ value >>>= 4;
+ }
+ }
+ return ByteBuffer.wrap(Arrays.copyOf(bytes, size));
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/HexStrings.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/HexStrings.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/HexStrings.java
new file mode 100644
index 0000000..ce65b8a
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/HexStrings.java
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.util.Random;
+
+import org.apache.cassandra.db.marshal.UTF8Type;
+
+public class HexStrings extends Generator<String>
+{
+ private final char[] chars;
+
+ public HexStrings(String name, GeneratorConfig config)
+ {
+ super(UTF8Type.instance, config, name);
+ chars = new char[(int) sizeDistribution.maxValue()];
+ }
+
+ @Override
+ public String generate()
+ {
+ long seed = identityDistribution.next();
+ sizeDistribution.setSeed(seed);
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i +=16)
+ {
+ long value = identityDistribution.next();
+ for (int j = 0 ; j < 16 && i + j < size ; j++)
+ {
+ int v = (int) (value & 15);
+ chars[i + j] = (char) ((v < 10 ? '0' : 'A') + v);
+ value >>>= 4;
+ }
+ }
+ return new String(chars, 0, size);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Inets.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Inets.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Inets.java
new file mode 100644
index 0000000..334d73c
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Inets.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.apache.cassandra.db.marshal.InetAddressType;
+
+
+public class Inets extends Generator<InetAddress>
+{
+ final byte[] buf;
+ public Inets(String name, GeneratorConfig config)
+ {
+ super(InetAddressType.instance, config, name);
+ buf = new byte[4];
+ }
+
+ @Override
+ public InetAddress generate()
+ {
+ int val = (int) identityDistribution.next();
+
+ buf[0] = (byte)(val >>> 24);
+ buf[1] = (byte)(val >>> 16);
+ buf[2] = (byte)(val >>> 8);
+ buf[3] = (byte)val;
+
+ try
+ {
+ return InetAddress.getByAddress(buf);
+ }
+ catch (UnknownHostException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Integers.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Integers.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Integers.java
new file mode 100644
index 0000000..8b9b33a
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Integers.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.Int32Type;
+
+public class Integers extends Generator<Integer>
+{
+
+ public Integers(String name, GeneratorConfig config)
+ {
+ super(Int32Type.instance, config, name);
+ }
+
+ @Override
+ public Integer generate()
+ {
+ return (int) identityDistribution.next();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
new file mode 100644
index 0000000..d188f7e
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.cassandra.db.marshal.ListType;
+
+public class Lists extends Generator<List>
+{
+ final Generator valueType;
+ final Object[] buffer;
+
+ public Lists(String name, Generator valueType, GeneratorConfig config)
+ {
+ super(ListType.getInstance(valueType.type), config, name);
+ this.valueType = valueType;
+ buffer = new Object[(int) sizeDistribution.maxValue()];
+ }
+
+ public void setSeed(long seed)
+ {
+ super.setSeed(seed);
+ valueType.setSeed(seed * 31);
+ }
+
+ @Override
+ public List generate()
+ {
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i++)
+ buffer[i] = valueType.generate();
+ return com.google.common.collect.Lists.newArrayList(Arrays.copyOf(buffer, size));
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Longs.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Longs.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Longs.java
new file mode 100644
index 0000000..0584ed1
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Longs.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.LongType;
+
+public class Longs extends Generator<Long>
+{
+ public Longs(String name, GeneratorConfig config)
+ {
+ super(LongType.instance, config, name);
+ }
+
+ @Override
+ public Long generate()
+ {
+ return identityDistribution.next();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
new file mode 100644
index 0000000..48bf293
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.cassandra.db.marshal.SetType;
+
+public class Sets extends Generator<Set>
+{
+ final Generator valueType;
+
+ public Sets(String name, Generator valueType, GeneratorConfig config)
+ {
+ super(SetType.getInstance(valueType.type), config, name);
+ this.valueType = valueType;
+ }
+
+ public void setSeed(long seed)
+ {
+ super.setSeed(seed);
+ valueType.setSeed(seed * 31);
+ }
+
+ @Override
+ public Set generate()
+ {
+ final Set set = new HashSet();
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i++)
+ set.add(valueType.generate());
+ return set;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Strings.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Strings.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Strings.java
new file mode 100644
index 0000000..e01ff20
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Strings.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.util.Random;
+
+import org.apache.cassandra.db.marshal.UTF8Type;
+
+public class Strings extends Generator<String>
+{
+ private final char[] chars;
+ private final Random rnd = new Random();
+
+ public Strings(String name, GeneratorConfig config)
+ {
+ super(UTF8Type.instance, config, name);
+ chars = new char[(int) sizeDistribution.maxValue()];
+ }
+
+ @Override
+ public String generate()
+ {
+ long seed = identityDistribution.next();
+ sizeDistribution.setSeed(seed);
+ rnd.setSeed(~seed);
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i++)
+ chars[i] = (char) (32 +rnd.nextInt(128-32));
+ return new String(chars, 0, size);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java
new file mode 100644
index 0000000..714959d
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+
+import org.apache.cassandra.db.marshal.TimeUUIDType;
+import org.apache.cassandra.utils.UUIDGen;
+
+import java.util.UUID;
+
+public class TimeUUIDs extends Generator<UUID>
+{
+ final Dates dateGen;
+ final long clockSeqAndNode;
+
+ public TimeUUIDs(String name, GeneratorConfig config)
+ {
+ super(TimeUUIDType.instance, config, name);
+ dateGen = new Dates(name, config);
+ clockSeqAndNode = config.salt;
+ }
+
+ public void setSeed(long seed)
+ {
+ dateGen.setSeed(seed);
+ }
+
+ @Override
+ public UUID generate()
+ {
+ return UUIDGen.getTimeUUID(dateGen.generate().getTime(), clockSeqAndNode);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/UUIDs.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/UUIDs.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/UUIDs.java
new file mode 100644
index 0000000..e8d6501
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/UUIDs.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.util.UUID;
+
+import org.apache.cassandra.db.marshal.UUIDType;
+
+public class UUIDs extends Generator<UUID>
+{
+ public UUIDs(String name, GeneratorConfig config)
+ {
+ super(UUIDType.instance, config, name);
+ }
+
+ @Override
+ public UUID generate()
+ {
+ return new UUID(identityDistribution.next(), identityDistribution.next());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGen.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGen.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGen.java
deleted file mode 100644
index 334506d..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGen.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.List;
-
-public abstract class DataGen
-{
-
- public abstract void generate(ByteBuffer fill, long index, ByteBuffer seed);
- public abstract boolean isDeterministic();
-
- public void generate(List<ByteBuffer> fills, long index, ByteBuffer seed)
- {
- for (ByteBuffer fill : fills)
- generate(fill, index++, seed);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenBytesRandom.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenBytesRandom.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenBytesRandom.java
deleted file mode 100644
index 1dc77b4..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenBytesRandom.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.Random;
-
-public class DataGenBytesRandom extends DataGen
-{
-
- private final Random rnd = new Random();
-
- @Override
- public void generate(ByteBuffer fill, long index, ByteBuffer seed)
- {
- fill.clear();
- rnd.nextBytes(fill.array());
- }
-
- @Override
- public boolean isDeterministic()
- {
- return false;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenFactory.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenFactory.java
deleted file mode 100644
index dadb792..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenFactory.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.Serializable;
-
-public interface DataGenFactory extends Serializable
-{
- DataGen get();
-}
-
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHex.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHex.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHex.java
deleted file mode 100644
index 124a07b..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHex.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-
-public abstract class DataGenHex extends DataGen
-{
-
- abstract long next(long operationIndex);
-
- @Override
- public final void generate(ByteBuffer fill, long operationIndex, ByteBuffer seed)
- {
- fill.clear();
- fillKeyStringBytes(next(operationIndex), fill.array());
- }
-
- public static void fillKeyStringBytes(long key, byte[] fill)
- {
- int ub = fill.length - 1;
- int offset = 0;
- while (key != 0)
- {
- int digit = ((int) key) & 15;
- key >>>= 4;
- fill[ub - offset++] = digit(digit);
- }
- while (offset < fill.length)
- fill[ub - offset++] = '0';
- }
-
- // needs to be UTF-8, but for these chars there is no difference
- private static byte digit(int num)
- {
- if (num < 10)
- return (byte)('0' + num);
- return (byte)('A' + (num - 10));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromDistribution.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromDistribution.java
deleted file mode 100644
index 25284dc..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromDistribution.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import org.apache.commons.math3.distribution.NormalDistribution;
-import org.apache.commons.math3.distribution.UniformRealDistribution;
-
-public class DataGenHexFromDistribution extends DataGenHex
-{
-
- final Distribution distribution;
-
- public DataGenHexFromDistribution(Distribution distribution)
- {
- this.distribution = distribution;
- }
-
- @Override
- public boolean isDeterministic()
- {
- return false;
- }
-
- @Override
- long next(long operationIndex)
- {
- return distribution.next();
- }
-
- public static DataGenHex buildGaussian(long minKey, long maxKey, double stdevsToLimit)
- {
- double midRange = (maxKey + minKey) / 2d;
- double halfRange = (maxKey - minKey) / 2d;
- return new DataGenHexFromDistribution(new DistributionBoundApache(new NormalDistribution(midRange, halfRange / stdevsToLimit), minKey, maxKey));
- }
-
- public static DataGenHex buildGaussian(long minKey, long maxKey, double mean, double stdev)
- {
- return new DataGenHexFromDistribution(new DistributionBoundApache(new NormalDistribution(mean, stdev), minKey, maxKey));
- }
-
- public static DataGenHex buildUniform(long minKey, long maxKey)
- {
- return new DataGenHexFromDistribution(new DistributionBoundApache(new UniformRealDistribution(minKey, maxKey), minKey, maxKey));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromOpIndex.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromOpIndex.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromOpIndex.java
deleted file mode 100644
index e6bda68..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromOpIndex.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-public class DataGenHexFromOpIndex extends DataGenHex
-{
-
- final long minKey;
- final long maxKey;
-
- public DataGenHexFromOpIndex(long minKey, long maxKey)
- {
- this.minKey = minKey;
- this.maxKey = maxKey;
- }
-
- @Override
- public boolean isDeterministic()
- {
- return true;
- }
-
- @Override
- long next(long operationIndex)
- {
- long range = maxKey + 1 - minKey;
- return Math.abs((operationIndex % range) + minKey);
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringDictionary.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringDictionary.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringDictionary.java
deleted file mode 100644
index 73814cb..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringDictionary.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.math3.distribution.EnumeratedDistribution;
-import org.apache.commons.math3.util.Pair;
-
-import static com.google.common.base.Charsets.UTF_8;
-
-public class DataGenStringDictionary extends DataGen
-{
-
- private final byte space = ' ';
- private final EnumeratedDistribution<byte[]> words;
-
- public DataGenStringDictionary(EnumeratedDistribution<byte[]> wordDistribution)
- {
- words = wordDistribution;
- }
-
- @Override
- public void generate(ByteBuffer fill, long index, ByteBuffer seed)
- {
- fill(fill);
- }
-
- @Override
- public void generate(List<ByteBuffer> fills, long index, ByteBuffer seed)
- {
- for (int i = 0 ; i < fills.size() ; i++)
- fill(fills.get(0));
- }
-
- private void fill(ByteBuffer fill)
- {
- fill.clear();
- byte[] trg = fill.array();
- int i = 0;
- while (i < trg.length)
- {
- if (i > 0)
- trg[i++] = space;
- byte[] src = words.sample();
- System.arraycopy(src, 0, trg, i, Math.min(src.length, trg.length - i));
- i += src.length;
- }
- }
-
- @Override
- public boolean isDeterministic()
- {
- return false;
- }
-
- public static DataGenFactory getFactory(File file) throws IOException
- {
- final List<Pair<byte[], Double>> words = new ArrayList<>();
- try (final BufferedReader reader = new BufferedReader(new FileReader(file)))
- {
- String line;
- while ( null != (line = reader.readLine()) )
- {
- String[] pair = line.split(" +");
- if (pair.length != 2)
- throw new IllegalArgumentException("Invalid record in dictionary: \"" + line + "\"");
- words.add(new Pair<>(pair[1].getBytes(UTF_8), Double.parseDouble(pair[0])));
- }
- final EnumeratedDistribution<byte[]> dist = new EnumeratedDistribution<byte[]>(words);
- return new DataGenFactory()
- {
- @Override
- public DataGen get()
- {
- return new DataGenStringDictionary(dist);
- }
- };
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringRepeats.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringRepeats.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringRepeats.java
deleted file mode 100644
index ad7cb24..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringRepeats.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.security.MessageDigest;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.cassandra.utils.FBUtilities;
-
-import static com.google.common.base.Charsets.UTF_8;
-
-public class DataGenStringRepeats extends DataGen
-{
-
- private static final ConcurrentHashMap<Integer, ConcurrentHashMap<Long, byte[]>> CACHE_LOOKUP = new ConcurrentHashMap<>();
-
- private final ConcurrentHashMap<Long, byte[]> cache;
- private final int repeatFrequency;
- public DataGenStringRepeats(int repeatFrequency)
- {
- if (!CACHE_LOOKUP.containsKey(repeatFrequency))
- CACHE_LOOKUP.putIfAbsent(repeatFrequency, new ConcurrentHashMap<Long, byte[]>());
- cache = CACHE_LOOKUP.get(repeatFrequency);
- this.repeatFrequency = repeatFrequency;
- }
-
- @Override
- public void generate(ByteBuffer fill, long index, ByteBuffer seed)
- {
- fill(fill, index, 0, seed);
- }
-
- @Override
- public void generate(List<ByteBuffer> fills, long index, ByteBuffer seed)
- {
- for (int i = 0 ; i < fills.size() ; i++)
- {
- fill(fills.get(i), index, i, seed);
- }
- }
-
- private void fill(ByteBuffer fill, long index, int column, ByteBuffer seed)
- {
- fill.clear();
- byte[] trg = fill.array();
- byte[] src = getData(index, column, seed);
- for (int j = 0 ; j < trg.length ; j += src.length)
- System.arraycopy(src, 0, trg, j, Math.min(src.length, trg.length - j));
- }
-
- private byte[] getData(long index, int column, ByteBuffer seed)
- {
- final long key = ((long)column * repeatFrequency) + ((seed == null ? index : Math.abs(seed.hashCode())) % repeatFrequency);
- byte[] r = cache.get(key);
- if (r != null)
- return r;
- MessageDigest md = FBUtilities.threadLocalMD5Digest();
- r = md.digest(Long.toString(key).getBytes(UTF_8));
- cache.putIfAbsent(key, r);
- return r;
- }
-
- @Override
- public boolean isDeterministic()
- {
- return true;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/Distribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/Distribution.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/Distribution.java
deleted file mode 100644
index ed40290..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/Distribution.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-public abstract class Distribution
-{
-
- public abstract long next();
- public abstract long inverseCumProb(double cumProb);
-
- public long maxValue()
- {
- return inverseCumProb(1d);
- }
-
- public long minValue()
- {
- return inverseCumProb(0d);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionBoundApache.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionBoundApache.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionBoundApache.java
deleted file mode 100644
index 0fdd437..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionBoundApache.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import org.apache.commons.math3.distribution.AbstractRealDistribution;
-
-public class DistributionBoundApache extends Distribution
-{
-
- final AbstractRealDistribution delegate;
- final long min, max;
-
- public DistributionBoundApache(AbstractRealDistribution delegate, long min, long max)
- {
- this.delegate = delegate;
- this.min = min;
- this.max = max;
- }
-
- @Override
- public long next()
- {
- return bound(min, max, delegate.sample());
- }
-
- @Override
- public long inverseCumProb(double cumProb)
- {
- return bound(min, max, delegate.inverseCumulativeProbability(cumProb));
- }
-
- private static long bound(long min, long max, double val)
- {
- long r = (long) val;
- if ((r >= min) & (r <= max))
- return r;
- if (r < min)
- return min;
- if (r > max)
- return max;
- throw new IllegalStateException();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFactory.java
deleted file mode 100644
index b80f851..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFactory.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.Serializable;
-
-public interface DistributionFactory extends Serializable
-{
-
- Distribution get();
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFixed.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFixed.java
deleted file mode 100644
index 43372ca..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFixed.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-public class DistributionFixed extends Distribution
-{
-
- final long key;
-
- public DistributionFixed(long key)
- {
- this.key = key;
- }
-
- @Override
- public long next()
- {
- return key;
- }
-
- @Override
- public long inverseCumProb(double cumProb)
- {
- return key;
- }
-
-}
[04/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionAnyProbabilities.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionAnyProbabilities.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionAnyProbabilities.java
new file mode 100644
index 0000000..a9af1bd
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionAnyProbabilities.java
@@ -0,0 +1,78 @@
+package org.apache.cassandra.stress.settings;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.math3.util.Pair;
+
+public final class OptionAnyProbabilities extends OptionMulti
+{
+ public OptionAnyProbabilities(String name, String description)
+ {
+ super(name, description, false);
+ }
+
+ final CollectRatios ratios = new CollectRatios();
+
+ private static final class CollectRatios extends Option
+ {
+ Map<String, Double> options = new LinkedHashMap<>();
+
+ boolean accept(String param)
+ {
+ String[] args = param.split("=");
+ if (args.length == 2 && args[1].length() > 0 && args[0].length() > 0)
+ {
+ if (options.put(args[0], Double.parseDouble(args[1])) != null)
+ throw new IllegalArgumentException(args[0] + " set twice");
+ return true;
+ }
+ return false;
+ }
+
+ boolean happy()
+ {
+ return !options.isEmpty();
+ }
+
+ String shortDisplay()
+ {
+ return null;
+ }
+
+ String longDisplay()
+ {
+ return null;
+ }
+
+ List<String> multiLineDisplay()
+ {
+ return Collections.emptyList();
+ }
+
+ boolean setByUser()
+ {
+ return !options.isEmpty();
+ }
+ }
+
+
+ @Override
+ public List<? extends Option> options()
+ {
+ return Arrays.asList(ratios);
+ }
+
+ List<Pair<String, Double>> ratios()
+ {
+ List<Pair<String, Double>> ratiosOut = new ArrayList<>();
+ for (Map.Entry<String, Double> e : ratios.options.entrySet())
+ ratiosOut.add(new Pair<String, Double>(e.getKey(), e.getValue()));
+ return ratiosOut;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java
deleted file mode 100644
index bde2b10..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java
+++ /dev/null
@@ -1,203 +0,0 @@
-package org.apache.cassandra.stress.settings;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.File;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.cassandra.stress.generatedata.*;
-
-/**
- * For selecting a data generator
- */
-class OptionDataGen extends Option
-{
-
- private static final Pattern FULL = Pattern.compile("([A-Z]+)\\(([^)]+)\\)", Pattern.CASE_INSENSITIVE);
- private static final Pattern ARGS = Pattern.compile("[^,]+");
-
- final String prefix;
- private DataGenFactory factory;
- private final DataGenFactory defaultFactory;
-
- public OptionDataGen(String prefix, String defaultSpec)
- {
- this.prefix = prefix;
- this.defaultFactory = defaultSpec == null ? null : get(defaultSpec);
- }
-
- @Override
- public boolean accept(String param)
- {
- if (!param.toLowerCase().startsWith(prefix))
- return false;
- factory = get(param.substring(prefix.length()));
- return true;
- }
-
- private static DataGenFactory get(String spec)
- {
- Matcher m = FULL.matcher(spec);
- if (!m.matches())
- throw new IllegalArgumentException("Illegal data generator specification: " + spec);
- String name = m.group(1);
- Impl impl = LOOKUP.get(name.toLowerCase());
- if (impl == null)
- throw new IllegalArgumentException("Illegal data generator type: " + name);
- List<String> params = new ArrayList<>();
- m = ARGS.matcher(m.group(2));
- while (m.find())
- params.add(m.group());
- return impl.getFactory(params);
- }
-
- public DataGenFactory get()
- {
- return factory != null ? factory : defaultFactory;
- }
-
- @Override
- public boolean happy()
- {
- return factory != null || defaultFactory != null;
- }
-
- public boolean setByUser()
- {
- return factory != null;
- }
-
- @Override
- public String shortDisplay()
- {
- return prefix + "ALG()";
- }
-
- public String longDisplay()
- {
- return shortDisplay() + ": Specify a data generator from:";
- }
-
- @Override
- public List<String> multiLineDisplay()
- {
- return Arrays.asList(
- GroupedOptions.formatMultiLine("RANDOM()", "Completely random byte generation"),
- GroupedOptions.formatMultiLine("REPEAT(<freq>)", "An MD5 hash of (opIndex % freq) combined with the column index"),
- GroupedOptions.formatMultiLine("DICT(<file>)","Random words from a dictionary; the file should be in the format \"<freq> <word>\"")
- );
- }
-
- private static final Map<String, Impl> LOOKUP;
- static
- {
- final Map<String, Impl> lookup = new HashMap<>();
- lookup.put("random", new RandomImpl());
- lookup.put("rand", new RandomImpl());
- lookup.put("rnd", new RandomImpl());
- lookup.put("repeat", new RepeatImpl());
- lookup.put("dict", new DictionaryImpl());
- lookup.put("dictionary", new DictionaryImpl());
- LOOKUP = lookup;
- }
-
- private static interface Impl
- {
- public DataGenFactory getFactory(List<String> params);
- }
-
- private static final class RandomImpl implements Impl
- {
- @Override
- public DataGenFactory getFactory(List<String> params)
- {
- if (params.size() != 0)
- throw new IllegalArgumentException("Invalid parameter list for random generator: " + params);
- return new RandomFactory();
- }
- }
-
- private static final class RepeatImpl implements Impl
- {
-
- @Override
- public DataGenFactory getFactory(List<String> params)
- {
- if (params.size() != 1)
- throw new IllegalArgumentException("Invalid parameter list for repeating generator: " + params);
- try
- {
- int repeatFrequency = Integer.parseInt(params.get(0));
- return new RepeatsFactory(repeatFrequency);
- } catch (Exception _)
- {
- throw new IllegalArgumentException("Invalid parameter list for repeating generator: " + params);
- }
- }
- }
-
- private static final class DictionaryImpl implements Impl
- {
-
- @Override
- public DataGenFactory getFactory(List<String> params)
- {
- if (params.size() != 1)
- throw new IllegalArgumentException("Invalid parameter list for dictionary generator: " + params);
- try
- {
- final File file = new File(params.get(0));
- return DataGenStringDictionary.getFactory(file);
- } catch (Exception e)
- {
- throw new IllegalArgumentException("Invalid parameter list for dictionary generator: " + params, e);
- }
- }
- }
-
- private static final class RandomFactory implements DataGenFactory
- {
- @Override
- public DataGen get()
- {
- return new DataGenBytesRandom();
- }
- }
-
- private static final class RepeatsFactory implements DataGenFactory
- {
- final int frequency;
- private RepeatsFactory(int frequency)
- {
- this.frequency = frequency;
- }
-
- @Override
- public DataGen get()
- {
- return new DataGenStringRepeats(frequency);
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java
----------------------------------------------------------------------
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 76fa0a9..70a85ae 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java
@@ -25,19 +25,20 @@ import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.apache.cassandra.stress.generatedata.*;
+import org.apache.cassandra.stress.generate.*;
import org.apache.commons.math3.distribution.ExponentialDistribution;
import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.commons.math3.distribution.UniformRealDistribution;
import org.apache.commons.math3.distribution.WeibullDistribution;
+import org.apache.commons.math3.random.JDKRandomGenerator;
/**
* For selecting a mathematical distribution
*/
-class OptionDistribution extends Option
+public class OptionDistribution extends Option
{
- private static final Pattern FULL = Pattern.compile("([A-Z]+)\\((.+)\\)", Pattern.CASE_INSENSITIVE);
+ private static final Pattern FULL = Pattern.compile("(~?)([A-Z]+)\\((.+)\\)", Pattern.CASE_INSENSITIVE);
private static final Pattern ARGS = Pattern.compile("[^,]+");
final String prefix;
@@ -61,20 +62,22 @@ class OptionDistribution extends Option
return true;
}
- private static DistributionFactory get(String spec)
+ public static DistributionFactory get(String spec)
{
Matcher m = FULL.matcher(spec);
if (!m.matches())
throw new IllegalArgumentException("Illegal distribution specification: " + spec);
- String name = m.group(1);
+ boolean inverse = m.group(1).equals("~");
+ String name = m.group(2);
Impl impl = LOOKUP.get(name.toLowerCase());
if (impl == null)
throw new IllegalArgumentException("Illegal distribution type: " + name);
List<String> params = new ArrayList<>();
- m = ARGS.matcher(m.group(2));
+ m = ARGS.matcher(m.group(3));
while (m.find())
params.add(m.group());
- return impl.getFactory(params);
+ DistributionFactory factory = impl.getFactory(params);
+ return inverse ? new InverseFactory(factory) : factory;
}
public DistributionFactory get()
@@ -103,6 +106,7 @@ class OptionDistribution extends Option
GroupedOptions.formatMultiLine("GAUSSIAN(min..max,mean,stdev)", "A gaussian/normal distribution, with explicitly defined mean and stdev"),
GroupedOptions.formatMultiLine("UNIFORM(min..max)", "A uniform distribution over the range [min, max]"),
GroupedOptions.formatMultiLine("FIXED(val)", "A fixed distribution, always returning the same value"),
+ "Preceding the name with ~ will invert the distribution, e.g. ~exp(1..10) will yield 10 most, instead of least, often",
"Aliases: extr, gauss, normal, norm, weibull"
);
}
@@ -142,6 +146,23 @@ class OptionDistribution extends Option
public DistributionFactory getFactory(List<String> params);
}
+ public static long parseLong(String value)
+ {
+ long multiplier = 1;
+ value = value.trim().toLowerCase();
+ switch (value.charAt(value.length() - 1))
+ {
+ case 'b':
+ multiplier *= 1000;
+ case 'm':
+ multiplier *= 1000;
+ case 'k':
+ multiplier *= 1000;
+ value = value.substring(0, value.length() - 1);
+ }
+ return Long.parseLong(value) * multiplier;
+ }
+
private static final class GaussianImpl implements Impl
{
@@ -153,8 +174,8 @@ class OptionDistribution extends Option
try
{
String[] bounds = params.get(0).split("\\.\\.+");
- final long min = Long.parseLong(bounds[0]);
- final long max = Long.parseLong(bounds[1]);
+ final long min = parseLong(bounds[0]);
+ final long max = parseLong(bounds[1]);
final double mean, stdev;
if (params.size() == 3)
{
@@ -185,8 +206,8 @@ class OptionDistribution extends Option
try
{
String[] bounds = params.get(0).split("\\.\\.+");
- final long min = Long.parseLong(bounds[0]);
- final long max = Long.parseLong(bounds[1]);
+ final long min = parseLong(bounds[0]);
+ final long max = parseLong(bounds[1]);
ExponentialDistribution findBounds = new ExponentialDistribution(1d);
// max probability should be roughly equal to accuracy of (max-min) to ensure all values are visitable,
// over entire range, but this results in overly skewed distribution, so take sqrt
@@ -209,8 +230,8 @@ class OptionDistribution extends Option
try
{
String[] bounds = params.get(0).split("\\.\\.+");
- final long min = Long.parseLong(bounds[0]);
- final long max = Long.parseLong(bounds[1]);
+ final long min = parseLong(bounds[0]);
+ final long max = parseLong(bounds[1]);
final double shape = Double.parseDouble(params.get(1));
WeibullDistribution findBounds = new WeibullDistribution(shape, 1d);
// max probability should be roughly equal to accuracy of (max-min) to ensure all values are visitable,
@@ -235,8 +256,8 @@ class OptionDistribution extends Option
try
{
String[] bounds = params.get(0).split("\\.\\.+");
- final long min = Long.parseLong(bounds[0]);
- final long max = Long.parseLong(bounds[1]);
+ final long min = parseLong(bounds[0]);
+ final long max = parseLong(bounds[1]);
return new UniformFactory(min, max);
} catch (Exception _)
{
@@ -255,7 +276,7 @@ class OptionDistribution extends Option
throw new IllegalArgumentException("Invalid parameter list for uniform distribution: " + params);
try
{
- final long key = Long.parseLong(params.get(0));
+ final long key = parseLong(params.get(0));
return new FixedFactory(key);
} catch (Exception _)
{
@@ -264,6 +285,20 @@ class OptionDistribution extends Option
}
}
+ private static final class InverseFactory implements DistributionFactory
+ {
+ final DistributionFactory wrapped;
+ private InverseFactory(DistributionFactory wrapped)
+ {
+ this.wrapped = wrapped;
+ }
+
+ public Distribution get()
+ {
+ return new DistributionInverted(wrapped.get());
+ }
+ }
+
// factories
private static final class ExpFactory implements DistributionFactory
@@ -280,7 +315,7 @@ class OptionDistribution extends Option
@Override
public Distribution get()
{
- return new DistributionOffsetApache(new ExponentialDistribution(mean), min, max);
+ return new DistributionOffsetApache(new ExponentialDistribution(new JDKRandomGenerator(), mean, ExponentialDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY), min, max);
}
}
@@ -299,7 +334,7 @@ class OptionDistribution extends Option
@Override
public Distribution get()
{
- return new DistributionOffsetApache(new WeibullDistribution(shape, scale), min, max);
+ return new DistributionOffsetApache(new WeibullDistribution(new JDKRandomGenerator(), shape, scale, WeibullDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY), min, max);
}
}
@@ -318,7 +353,7 @@ class OptionDistribution extends Option
@Override
public Distribution get()
{
- return new DistributionBoundApache(new NormalDistribution(mean, stdev), min, max);
+ return new DistributionBoundApache(new NormalDistribution(new JDKRandomGenerator(), mean, stdev, NormalDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY), min, max);
}
}
@@ -334,7 +369,7 @@ class OptionDistribution extends Option
@Override
public Distribution get()
{
- return new DistributionBoundApache(new UniformRealDistribution(min, max + 1), min, max);
+ return new DistributionBoundApache(new UniformRealDistribution(new JDKRandomGenerator(), min, max + 1), min, max);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionEnumProbabilities.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionEnumProbabilities.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionEnumProbabilities.java
new file mode 100644
index 0000000..88ebd34
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionEnumProbabilities.java
@@ -0,0 +1,62 @@
+package org.apache.cassandra.stress.settings;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math3.util.Pair;
+
+public final class OptionEnumProbabilities<T> extends OptionMulti
+{
+ final List<OptMatcher<T>> options;
+
+ public static class Opt<T>
+ {
+ final T option;
+ final String defaultValue;
+
+ public Opt(T option, String defaultValue)
+ {
+ this.option = option;
+ this.defaultValue = defaultValue;
+ }
+ }
+
+ private static final class OptMatcher<T> extends OptionSimple
+ {
+ final T opt;
+ OptMatcher(T opt, String defaultValue)
+ {
+ super(opt.toString().toLowerCase() + "=", "[0-9]+(\\.[0-9]+)?", defaultValue, "Performs this many " + opt + " operations out of total", false);
+ this.opt = opt;
+ }
+ }
+
+ public OptionEnumProbabilities(List<Opt<T>> universe, String name, String description)
+ {
+ super(name, description, false);
+ List<OptMatcher<T>> options = new ArrayList<>();
+ for (Opt<T> option : universe)
+ options.add(new OptMatcher<T>(option.option, option.defaultValue));
+ this.options = options;
+ }
+
+ @Override
+ public List<? extends Option> options()
+ {
+ return options;
+ }
+
+ List<Pair<T, Double>> ratios()
+ {
+ List<? extends Option> ratiosIn = setByUser() ? optionsSetByUser() : defaultOptions();
+ List<Pair<T, Double>> ratiosOut = new ArrayList<>();
+ for (Option opt : ratiosIn)
+ {
+ OptMatcher<T> optMatcher = (OptMatcher<T>) opt;
+ double d = Double.parseDouble(optMatcher.value());
+ ratiosOut.add(new Pair<>(optMatcher.opt, d));
+ }
+ return ratiosOut;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java
----------------------------------------------------------------------
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 60faad8..32bfc65 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java
@@ -156,7 +156,8 @@ abstract class OptionMulti extends Option
String[] args = param.split("=");
if (args.length == 2 && args[1].length() > 0 && args[0].length() > 0)
{
- options.put(args[0], args[1]);
+ if (options.put(args[0], args[1]) != null)
+ throw new IllegalArgumentException(args[0] + " set twice");
return true;
}
return false;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionRatioDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionRatioDistribution.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionRatioDistribution.java
new file mode 100644
index 0000000..2459c20
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionRatioDistribution.java
@@ -0,0 +1,166 @@
+package org.apache.cassandra.stress.settings;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.math3.distribution.ExponentialDistribution;
+import org.apache.commons.math3.distribution.NormalDistribution;
+import org.apache.commons.math3.distribution.UniformRealDistribution;
+import org.apache.commons.math3.distribution.WeibullDistribution;
+import org.apache.commons.math3.random.JDKRandomGenerator;
+
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionBoundApache;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.DistributionFixed;
+import org.apache.cassandra.stress.generate.DistributionInverted;
+import org.apache.cassandra.stress.generate.DistributionOffsetApache;
+import org.apache.cassandra.stress.generate.RatioDistribution;
+import org.apache.cassandra.stress.generate.RatioDistributionFactory;
+
+/**
+ * For selecting a mathematical distribution
+ */
+public class OptionRatioDistribution extends Option
+{
+
+ private static final Pattern FULL = Pattern.compile("(.*)/([0-9]+[KMB]?)", Pattern.CASE_INSENSITIVE);
+
+ final OptionDistribution delegate;
+ private double divisor;
+
+ private static final RatioDistribution DEFAULT = new RatioDistribution(new DistributionFixed(1), 1);
+
+ public OptionRatioDistribution(String prefix, String defaultSpec, String description)
+ {
+ delegate = new OptionDistribution(prefix, defaultSpec, description);
+ }
+
+ @Override
+ public boolean accept(String param)
+ {
+ Matcher m = FULL.matcher(param);
+ if (!m.matches() || !delegate.accept(m.group(1)))
+ return false;
+ divisor = OptionDistribution.parseLong(m.group(2));
+ return true;
+ }
+
+ public static RatioDistributionFactory get(String spec)
+ {
+ OptionRatioDistribution opt = new OptionRatioDistribution("", "", "");
+ if (!opt.accept(spec))
+ throw new IllegalArgumentException();
+ return opt.get();
+ }
+
+ public RatioDistributionFactory get()
+ {
+ return !delegate.setByUser() ? new DefaultFactory() : new DelegateFactory(delegate.get(), divisor);
+ }
+
+ @Override
+ public boolean happy()
+ {
+ return delegate.happy();
+ }
+
+ public String longDisplay()
+ {
+ return delegate.longDisplay();
+ }
+
+ @Override
+ public List<String> multiLineDisplay()
+ {
+ return Arrays.asList(
+ GroupedOptions.formatMultiLine("EXP(min..max)/divisor", "An exponential ratio distribution over the range [min..max]/divisor"),
+ GroupedOptions.formatMultiLine("EXTREME(min..max,shape)/divisor", "An extreme value (Weibull) ratio distribution over the range [min..max]/divisor"),
+ GroupedOptions.formatMultiLine("GAUSSIAN(min..max,stdvrng)/divisor", "A gaussian/normal ratio distribution, where mean=(min+max)/2, and stdev is ((mean-min)/stdvrng)/divisor"),
+ GroupedOptions.formatMultiLine("GAUSSIAN(min..max,mean,stdev)/divisor", "A gaussian/normal ratio distribution, with explicitly defined mean and stdev"),
+ GroupedOptions.formatMultiLine("UNIFORM(min..max)/divisor", "A uniform ratio distribution over the range [min, max]/divisor"),
+ GroupedOptions.formatMultiLine("FIXED(val)/divisor", "A fixed ratio distribution, always returning the same value"),
+ "Preceding the name with ~ will invert the distribution, e.g. ~exp(1..10)/10 will yield 0.1 least, instead of most, often",
+ "Aliases: extr, gauss, normal, norm, weibull"
+ );
+ }
+
+ boolean setByUser()
+ {
+ return delegate.setByUser();
+ }
+
+ @Override
+ public String shortDisplay()
+ {
+ return delegate.shortDisplay();
+ }
+
+ // factories
+
+ private static final class DefaultFactory implements RatioDistributionFactory
+ {
+ @Override
+ public RatioDistribution get()
+ {
+ return DEFAULT;
+ }
+ }
+
+ private static final class DelegateFactory implements RatioDistributionFactory
+ {
+ final DistributionFactory delegate;
+ final double divisor;
+
+ private DelegateFactory(DistributionFactory delegate, double divisor)
+ {
+ this.delegate = delegate;
+ this.divisor = divisor;
+ }
+
+ @Override
+ public RatioDistribution get()
+ {
+ return new RatioDistribution(delegate.get(), divisor);
+ }
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object that)
+ {
+ return super.equals(that) && ((OptionRatioDistribution) that).delegate.equals(this.delegate);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java
index 9365e45..71c1ffe 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java
@@ -21,6 +21,7 @@ package org.apache.cassandra.stress.settings;
*/
+import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
@@ -30,7 +31,7 @@ import com.google.common.base.Function;
/**
* For parsing a simple (sub)option for a command/major option
*/
-class OptionSimple extends Option
+class OptionSimple extends Option implements Serializable
{
final String displayPrefix;
@@ -41,7 +42,7 @@ class OptionSimple extends Option
private final boolean required;
private String value;
- private static final class ValueMatcher implements Function<String, String>
+ private static final class ValueMatcher implements Function<String, String>, Serializable
{
final Pattern pattern;
private ValueMatcher(Pattern pattern)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
index 7e20ec6..04c2a47 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
@@ -23,13 +23,15 @@ package org.apache.cassandra.stress.settings;
import java.io.Serializable;
import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.cassandra.db.marshal.*;
-import org.apache.cassandra.stress.generatedata.*;
+import org.apache.cassandra.stress.generate.*;
import org.apache.cassandra.utils.ByteBufferUtil;
/**
@@ -39,17 +41,13 @@ public class SettingsColumn implements Serializable
{
public final int maxColumnsPerKey;
- public final List<ByteBuffer> names;
+ public transient final List<ByteBuffer> names;
public final List<String> namestrs;
public final String comparator;
- public final boolean useTimeUUIDComparator;
- public final int superColumns;
- public final boolean useSuperColumns;
public final boolean variableColumnCount;
public final boolean slice;
- private final DistributionFactory sizeDistribution;
- private final DistributionFactory countDistribution;
- private final DataGenFactory dataGenFactory;
+ public final DistributionFactory sizeDistribution;
+ public final DistributionFactory countDistribution;
public SettingsColumn(GroupedOptions options)
{
@@ -62,9 +60,6 @@ public class SettingsColumn implements Serializable
public SettingsColumn(Options options, NameOptions name, CountOptions count)
{
sizeDistribution = options.size.get();
- superColumns = Integer.parseInt(options.superColumns.value());
- dataGenFactory = options.generator.get();
- useSuperColumns = superColumns > 0;
{
comparator = options.comparator.value();
AbstractType parsed = null;
@@ -79,8 +74,6 @@ public class SettingsColumn implements Serializable
System.exit(1);
}
- useTimeUUIDComparator = parsed instanceof TimeUUIDType;
-
if (!(parsed instanceof TimeUUIDType || parsed instanceof AsciiType || parsed instanceof UTF8Type))
{
System.err.println("Currently supported types are: TimeUUIDType, AsciiType, UTF8Type.");
@@ -102,10 +95,13 @@ public class SettingsColumn implements Serializable
final String[] names = name.name.value().split(",");
this.names = new ArrayList<>(names.length);
- this.namestrs = Arrays.asList(names);
for (String columnName : names)
this.names.add(comparator.fromString(columnName));
+ Collections.sort(this.names, BytesType.instance);
+ this.namestrs = new ArrayList<>();
+ for (ByteBuffer columnName : this.names)
+ this.namestrs.add(comparator.getString(columnName));
final int nameCount = this.names.size();
countDistribution = new DistributionFactory()
@@ -123,23 +119,24 @@ public class SettingsColumn implements Serializable
ByteBuffer[] names = new ByteBuffer[(int) countDistribution.get().maxValue()];
String[] namestrs = new String[(int) countDistribution.get().maxValue()];
for (int i = 0 ; i < names.length ; i++)
- {
names[i] = ByteBufferUtil.bytes("C" + i);
- namestrs[i] = "C" + i;
+ Arrays.sort(names, BytesType.instance);
+ try
+ {
+ for (int i = 0 ; i < names.length ; i++)
+ namestrs[i] = ByteBufferUtil.string(names[i]);
+ }
+ catch (CharacterCodingException e)
+ {
+ throw new RuntimeException(e);
}
+
this.names = Arrays.asList(names);
this.namestrs = Arrays.asList(namestrs);
}
maxColumnsPerKey = (int) countDistribution.get().maxValue();
variableColumnCount = countDistribution.get().minValue() < maxColumnsPerKey;
- // TODO: should warn that we always slice for useTimeUUIDComparator?
- slice = options.slice.setByUser() || useTimeUUIDComparator;
- // TODO: with useTimeUUIDCOmparator, should we still try to select a random start for reads if possible?
- }
-
- public RowGen newRowGen()
- {
- return new RowGenDistributedSize(dataGenFactory.get(), countDistribution.get(), sizeDistribution.get());
+ slice = options.slice.setByUser();
}
// Option Declarations
@@ -150,7 +147,6 @@ public class SettingsColumn implements Serializable
final OptionSimple comparator = new OptionSimple("comparator=", "TimeUUIDType|AsciiType|UTF8Type", "AsciiType", "Column Comparator to use", false);
final OptionSimple slice = new OptionSimple("slice", "", null, "If set, range slices will be used for reads, otherwise a names query will be", false);
final OptionDistribution size = new OptionDistribution("size=", "FIXED(34)", "Cell size distribution");
- final OptionDataGen generator = new OptionDataGen("data=", "REPEAT(50)");
}
private static final class NameOptions extends Options
@@ -160,7 +156,7 @@ public class SettingsColumn implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(name, slice, superColumns, comparator, size, generator);
+ return Arrays.asList(name, slice, superColumns, comparator, size);
}
}
@@ -171,7 +167,7 @@ public class SettingsColumn implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(count, slice, superColumns, comparator, size, generator);
+ return Arrays.asList(count, slice, superColumns, comparator, size);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
index b491707..032f00c 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
@@ -26,23 +26,24 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import org.apache.cassandra.stress.generatedata.DistributionFactory;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
import org.apache.cassandra.thrift.ConsistencyLevel;
// Generic command settings - common to read/write/etc
-public class SettingsCommand implements Serializable
+public abstract class SettingsCommand implements Serializable
{
public final Command type;
public final long count;
public final int tries;
public final boolean ignoreErrors;
+ public final boolean noWarmup;
public final ConsistencyLevel consistencyLevel;
public final double targetUncertainty;
public final int minimumUncertaintyMeasurements;
public final int maximumUncertaintyMeasurements;
- public final DistributionFactory add;
- public final int keysAtOnce;
+
+ public abstract OpDistributionFactory getFactory(StressSettings settings);
public SettingsCommand(Command type, GroupedOptions options)
{
@@ -58,8 +59,7 @@ public class SettingsCommand implements Serializable
this.tries = Math.max(1, Integer.parseInt(options.retries.value()) + 1);
this.ignoreErrors = options.ignoreErrors.setByUser();
this.consistencyLevel = ConsistencyLevel.valueOf(options.consistencyLevel.value().toUpperCase());
- this.keysAtOnce = Integer.parseInt(options.atOnce.value());
- this.add = options.add.get();
+ this.noWarmup = options.noWarmup.setByUser();
if (count != null)
{
this.count = Long.parseLong(count.count.value());
@@ -82,8 +82,8 @@ public class SettingsCommand implements Serializable
{
final OptionSimple retries = new OptionSimple("tries=", "[0-9]+", "9", "Number of tries to perform for each operation before failing", false);
final OptionSimple ignoreErrors = new OptionSimple("ignore_errors", "", null, "Do not print/log errors", false);
+ final OptionSimple noWarmup = new OptionSimple("no_warmup", "", null, "Do not warmup the process", false);
final OptionSimple consistencyLevel = new OptionSimple("cl=", "ONE|QUORUM|LOCAL_QUORUM|EACH_QUORUM|ALL|ANY", "ONE", "Consistency level to use", false);
- final OptionDistribution add = new OptionDistribution("add=", "fixed(1)", "Distribution of value of counter increments");
final OptionSimple atOnce = new OptionSimple("at-once=", "[0-9]+", "1000", "Number of keys per operation for multiget", false);
}
@@ -93,7 +93,7 @@ public class SettingsCommand implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(count, retries, ignoreErrors, consistencyLevel, add, atOnce);
+ return Arrays.asList(count, retries, noWarmup, ignoreErrors, consistencyLevel, atOnce);
}
}
@@ -105,7 +105,7 @@ public class SettingsCommand implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(uncertainty, minMeasurements, maxMeasurements, retries, ignoreErrors, consistencyLevel, add, atOnce);
+ return Arrays.asList(uncertainty, minMeasurements, maxMeasurements, retries, noWarmup, ignoreErrors, consistencyLevel, atOnce);
}
}
@@ -127,48 +127,16 @@ public class SettingsCommand implements Serializable
switch (cmd.category)
{
case BASIC:
- case MULTI:
- return build(cmd, params);
+ return SettingsCommandPreDefined.build(cmd, params);
case MIXED:
- return SettingsCommandMixed.build(params);
+ return SettingsCommandPreDefinedMixed.build(params);
+ case USER:
+ return SettingsCommandUser.build(params);
}
}
}
return null;
}
- static SettingsCommand build(Command type, String[] params)
- {
- GroupedOptions options = GroupedOptions.select(params, new Count(), new Uncertainty());
- if (options == null)
- {
- printHelp(type);
- System.out.println("Invalid " + type + " options provided, see output for valid options");
- System.exit(1);
- }
- return new SettingsCommand(type, options);
- }
-
- static void printHelp(Command type)
- {
- printHelp(type.toString().toLowerCase());
- }
-
- static void printHelp(String type)
- {
- GroupedOptions.printOptions(System.out, type.toLowerCase(), new Uncertainty(), new Count());
- }
-
- static Runnable helpPrinter(final Command type)
- {
- return new Runnable()
- {
- @Override
- public void run()
- {
- printHelp(type);
- }
- };
- }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMixed.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMixed.java
deleted file mode 100644
index 3f16425..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMixed.java
+++ /dev/null
@@ -1,207 +0,0 @@
-package org.apache.cassandra.stress.settings;
-/*
- *
- * 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.
- *
- */
-
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.cassandra.stress.generatedata.Distribution;
-import org.apache.cassandra.stress.generatedata.DistributionFactory;
-
-import org.apache.commons.math3.distribution.EnumeratedDistribution;
-import org.apache.commons.math3.util.Pair;
-
-// Settings unique to the mixed command type
-public class SettingsCommandMixed extends SettingsCommand
-{
-
- // Ratios for selecting commands - index for each Command, NaN indicates the command is not requested
- private final List<Pair<Command, Double>> ratios;
- private final DistributionFactory clustering;
-
- public SettingsCommandMixed(Options options)
- {
- super(Command.MIXED, options.parent);
-
- clustering = options.clustering.get();
- ratios = options.probabilities.ratios();
- if (ratios.size() == 0)
- throw new IllegalArgumentException("Must specify at least one command with a non-zero ratio");
- }
-
- public List<Command> getCommands()
- {
- final List<Command> r = new ArrayList<>();
- for (Pair<Command, Double> p : ratios)
- r.add(p.getFirst());
- return r;
- }
-
- public CommandSelector selector()
- {
- return new CommandSelector(ratios, clustering.get());
- }
-
- // Class for randomly selecting the next command type
-
- public static final class CommandSelector
- {
-
- final EnumeratedDistribution<Command> selector;
- final Distribution count;
- private Command cur;
- private long remaining;
-
- public CommandSelector(List<Pair<Command, Double>> ratios, Distribution count)
- {
- selector = new EnumeratedDistribution<>(ratios);
- this.count = count;
- }
-
- public Command next()
- {
- while (remaining == 0)
- {
- remaining = count.next();
- cur = selector.sample();
- }
- remaining--;
- return cur;
- }
- }
-
- // Option Declarations
-
- static final class Probabilities extends OptionMulti
- {
- // entry for each in Command.values()
- final OptionSimple[] ratios;
- final List<OptionSimple> grouping;
-
- public Probabilities()
- {
- super("ratio", "Specify the ratios for operations to perform; e.g. (reads=2,writes=1) will perform 2 reads for each write", false);
- OptionSimple[] ratios = new OptionSimple[Command.values().length];
- List<OptionSimple> grouping = new ArrayList<>();
- for (Command command : Command.values())
- {
- if (command.category == null)
- continue;
- String defaultValue;
- switch (command)
- {
- case MIXED:
- continue;
- case READ:
- case WRITE:
- defaultValue = "1";
- break;
- default:
- defaultValue = null;
- }
- OptionSimple ratio = new OptionSimple(command.toString().toLowerCase() +
- "=", "[0-9]+(\\.[0-9]+)?", defaultValue, "Performs this many " + command + " operations out of total", false);
- ratios[command.ordinal()] = ratio;
- grouping.add(ratio);
- }
- this.grouping = grouping;
- this.ratios = ratios;
- }
-
- @Override
- public List<? extends Option> options()
- {
- return grouping;
- }
-
- List<Pair<Command, Double>> ratios()
- {
- List<? extends Option> ratiosIn = setByUser() ? optionsSetByUser() : defaultOptions();
- List<Pair<Command, Double>> ratiosOut = new ArrayList<>();
- for (Option opt : ratiosIn)
- {
- OptionSimple ratioIn = (OptionSimple) opt;
- Command command = Command.get(ratioIn.displayPrefix.substring(0, ratioIn.displayPrefix.length() - 1));
- double d = Double.parseDouble(ratioIn.value());
- ratiosOut.add(new Pair<>(command, d));
- }
- return ratiosOut;
- }
- }
-
- static final class Options extends GroupedOptions
- {
- final SettingsCommand.Options parent;
- protected Options(SettingsCommand.Options parent)
- {
- this.parent = parent;
- }
- final OptionDistribution clustering = new OptionDistribution("clustering=", "GAUSSIAN(1..10)", "Distribution clustering runs of operations of the same kind");
- final Probabilities probabilities = new Probabilities();
-
- @Override
- public List<? extends Option> options()
- {
- final List<Option> options = new ArrayList<>();
- options.add(clustering);
- options.add(probabilities);
- options.addAll(parent.options());
- return options;
- }
-
- }
-
- // CLI utility methods
-
- public static SettingsCommandMixed build(String[] params)
- {
- GroupedOptions options = GroupedOptions.select(params,
- new Options(new SettingsCommand.Uncertainty()),
- new Options(new SettingsCommand.Count()));
- if (options == null)
- {
- printHelp();
- System.out.println("Invalid MIXED options provided, see output for valid options");
- System.exit(1);
- }
- return new SettingsCommandMixed((Options) options);
- }
-
- public static void printHelp()
- {
- GroupedOptions.printOptions(System.out, "mixed",
- new Options(new SettingsCommand.Uncertainty()),
- new Options(new SettingsCommand.Count()));
- }
-
- public static Runnable helpPrinter()
- {
- return new Runnable()
- {
- @Override
- public void run()
- {
- printHelp();
- }
- };
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
new file mode 100644
index 0000000..ac113d1
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
@@ -0,0 +1,145 @@
+package org.apache.cassandra.stress.settings;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.values.Bytes;
+import org.apache.cassandra.stress.generate.values.Generator;
+import org.apache.cassandra.stress.generate.values.GeneratorConfig;
+import org.apache.cassandra.stress.generate.values.HexBytes;
+import org.apache.cassandra.stress.operations.FixedOpDistribution;
+import org.apache.cassandra.stress.operations.OpDistribution;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
+import org.apache.cassandra.stress.operations.predefined.PredefinedOperation;
+import org.apache.cassandra.stress.util.Timer;
+
+// Settings unique to the mixed command type
+public class SettingsCommandPreDefined extends SettingsCommand
+{
+
+ public final DistributionFactory add;
+
+ public OpDistributionFactory getFactory(final StressSettings settings)
+ {
+ return new OpDistributionFactory()
+ {
+ public OpDistribution get(Timer timer)
+ {
+ return new FixedOpDistribution(PredefinedOperation.operation(type, timer, newGenerator(settings), settings, add));
+ }
+
+ public String desc()
+ {
+ return type.toString();
+ }
+
+ public Iterable<OpDistributionFactory> each()
+ {
+ return Collections.<OpDistributionFactory>singleton(this);
+ }
+ };
+ }
+
+ PartitionGenerator newGenerator(StressSettings settings)
+ {
+ List<String> names = settings.columns.namestrs;
+ List<Generator> partitionKey = Collections.<Generator>singletonList(new HexBytes("key",
+ new GeneratorConfig("randomstrkey", null,
+ OptionDistribution.get("fixed(" + settings.keys.keySize + ")"), null)));
+
+ List<Generator> columns = new ArrayList<>();
+ for (int i = 0 ; i < settings.columns.maxColumnsPerKey ; i++)
+ columns.add(new Bytes(names.get(i), new GeneratorConfig("randomstr" + names.get(i), null, settings.columns.sizeDistribution, null)));
+ return new PartitionGenerator(partitionKey, Collections.<Generator>emptyList(), columns);
+ }
+
+ public SettingsCommandPreDefined(Command type, Options options)
+ {
+ super(type, options.parent);
+ add = options.add.get();
+ }
+
+ // Option Declarations
+
+ static class Options extends GroupedOptions
+ {
+ final SettingsCommand.Options parent;
+ protected Options(SettingsCommand.Options parent)
+ {
+ this.parent = parent;
+ }
+ final OptionDistribution add = new OptionDistribution("add=", "fixed(1)", "Distribution of value of counter increments");
+
+ @Override
+ public List<? extends Option> options()
+ {
+ final List<Option> options = new ArrayList<>();
+ options.addAll(parent.options());
+ options.add(add);
+ return options;
+ }
+
+ }
+
+ // CLI utility methods
+
+ public static SettingsCommandPreDefined build(Command type, String[] params)
+ {
+ GroupedOptions options = GroupedOptions.select(params,
+ new Options(new Uncertainty()),
+ new Options(new Count()));
+ if (options == null)
+ {
+ printHelp(type);
+ System.out.println("Invalid " + type + " options provided, see output for valid options");
+ System.exit(1);
+ }
+ return new SettingsCommandPreDefined(type, (Options) options);
+ }
+
+ static void printHelp(Command type)
+ {
+ printHelp(type.toString().toLowerCase());
+ }
+
+ static void printHelp(String type)
+ {
+ GroupedOptions.printOptions(System.out, type.toLowerCase(), new Uncertainty(), new Count());
+ }
+
+ static Runnable helpPrinter(final Command type)
+ {
+ return new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ printHelp(type);
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
new file mode 100644
index 0000000..e5d4f80
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
@@ -0,0 +1,151 @@
+package org.apache.cassandra.stress.settings;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
+import org.apache.cassandra.stress.operations.SampledOpDistributionFactory;
+import org.apache.cassandra.stress.operations.predefined.PredefinedOperation;
+import org.apache.cassandra.stress.util.Timer;
+
+import org.apache.commons.math3.util.Pair;
+
+// Settings unique to the mixed command type
+public class SettingsCommandPreDefinedMixed extends SettingsCommandPreDefined
+{
+
+ // Ratios for selecting commands - index for each Command, NaN indicates the command is not requested
+ private final List<Pair<Command, Double>> ratios;
+ private final DistributionFactory clustering;
+
+ public SettingsCommandPreDefinedMixed(Options options)
+ {
+ super(Command.MIXED, options);
+
+ clustering = options.clustering.get();
+ ratios = options.probabilities.ratios();
+ if (ratios.size() == 0)
+ throw new IllegalArgumentException("Must specify at least one command with a non-zero ratio");
+ }
+
+ public OpDistributionFactory getFactory(final StressSettings settings)
+ {
+ return new SampledOpDistributionFactory<Command>(ratios, clustering)
+ {
+ protected Operation get(Timer timer, PartitionGenerator generator, Command key)
+ {
+ return PredefinedOperation.operation(key, timer, generator, settings, add);
+ }
+
+ protected PartitionGenerator newGenerator()
+ {
+ return SettingsCommandPreDefinedMixed.this.newGenerator(settings);
+ }
+ };
+ }
+
+ // Option Declarations
+
+ static class Options extends SettingsCommandPreDefined.Options
+ {
+ static List<OptionEnumProbabilities.Opt<Command>> probabilityOptions = new ArrayList<>();
+ static
+ {
+ for (Command command : Command.values())
+ {
+ if (command.category == null)
+ continue;
+ String defaultValue;
+ switch (command)
+ {
+ case MIXED:
+ continue;
+ case READ:
+ case WRITE:
+ defaultValue = "1";
+ break;
+ default:
+ defaultValue = null;
+ }
+ probabilityOptions.add(new OptionEnumProbabilities.Opt<>(command, defaultValue));
+ }
+ }
+
+ protected Options(SettingsCommand.Options parent)
+ {
+ super(parent);
+ }
+ final OptionDistribution clustering = new OptionDistribution("clustering=", "GAUSSIAN(1..10)", "Distribution clustering runs of operations of the same kind");
+ final OptionEnumProbabilities probabilities = new OptionEnumProbabilities<>(probabilityOptions, "ratio", "Specify the ratios for operations to perform; e.g. (read=2,write=1) will perform 2 reads for each write");
+
+ @Override
+ public List<? extends Option> options()
+ {
+ final List<Option> options = new ArrayList<>();
+ options.add(clustering);
+ options.add(probabilities);
+ options.addAll(super.options());
+ return options;
+ }
+
+ }
+
+ // CLI utility methods
+
+ public static SettingsCommandPreDefinedMixed build(String[] params)
+ {
+ GroupedOptions options = GroupedOptions.select(params,
+ new Options(new SettingsCommand.Uncertainty()),
+ new Options(new SettingsCommand.Count()));
+ if (options == null)
+ {
+ printHelp();
+ System.out.println("Invalid MIXED options provided, see output for valid options");
+ System.exit(1);
+ }
+ return new SettingsCommandPreDefinedMixed((Options) options);
+ }
+
+ public static void printHelp()
+ {
+ GroupedOptions.printOptions(System.out, "mixed",
+ new Options(new SettingsCommand.Uncertainty()),
+ new Options(new SettingsCommand.Count()));
+ }
+
+ public static Runnable helpPrinter()
+ {
+ return new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ printHelp();
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
new file mode 100644
index 0000000..f36296e
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
@@ -0,0 +1,135 @@
+package org.apache.cassandra.stress.settings;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math3.util.Pair;
+
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.StressProfile;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
+import org.apache.cassandra.stress.operations.SampledOpDistributionFactory;
+import org.apache.cassandra.stress.util.Timer;
+
+// Settings unique to the mixed command type
+public class SettingsCommandUser extends SettingsCommand
+{
+
+ // Ratios for selecting commands - index for each Command, NaN indicates the command is not requested
+ private final List<Pair<String, Double>> ratios;
+ private final DistributionFactory clustering;
+ public final StressProfile profile;
+
+ public SettingsCommandUser(Options options)
+ {
+ super(Command.USER, options.parent);
+
+ clustering = options.clustering.get();
+ ratios = options.ops.ratios();
+ profile = StressProfile.load(new File(options.profile.value()));
+
+ if (ratios.size() == 0)
+ throw new IllegalArgumentException("Must specify at least one command with a non-zero ratio");
+ }
+
+ public OpDistributionFactory getFactory(final StressSettings settings)
+ {
+ return new SampledOpDistributionFactory<String>(ratios, clustering)
+ {
+ protected Operation get(Timer timer, PartitionGenerator generator, String key)
+ {
+ if (key.equalsIgnoreCase("insert"))
+ return profile.getInsert(timer, generator, settings);
+ return profile.getQuery(key, timer, generator, settings);
+ }
+
+ protected PartitionGenerator newGenerator()
+ {
+ return profile.newGenerator(settings);
+ }
+ };
+ }
+
+ static final class Options extends GroupedOptions
+ {
+ final SettingsCommand.Options parent;
+ protected Options(SettingsCommand.Options parent)
+ {
+ this.parent = parent;
+ }
+ final OptionDistribution clustering = new OptionDistribution("clustering=", "GAUSSIAN(1..10)", "Distribution clustering runs of operations of the same kind");
+ final OptionSimple profile = new OptionSimple("profile=", ".*", null, "Specify the path to a yaml cql3 profile", false);
+ final OptionAnyProbabilities ops = new OptionAnyProbabilities("ops", "Specify the ratios for inserts/queries to perform; e.g. ops(insert=2,<query1>=1) will perform 2 inserts for each query1");
+
+ @Override
+ public List<? extends Option> options()
+ {
+ final List<Option> options = new ArrayList<>();
+ options.add(clustering);
+ options.add(ops);
+ options.add(profile);
+ options.addAll(parent.options());
+ return options;
+ }
+
+ }
+
+ // CLI utility methods
+
+ public static SettingsCommandUser build(String[] params)
+ {
+ GroupedOptions options = GroupedOptions.select(params,
+ new Options(new Uncertainty()),
+ new Options(new Count()));
+ if (options == null)
+ {
+ printHelp();
+ System.out.println("Invalid USER options provided, see output for valid options");
+ System.exit(1);
+ }
+ return new SettingsCommandUser((Options) options);
+ }
+
+ public static void printHelp()
+ {
+ GroupedOptions.printOptions(System.out, "user",
+ new Options(new Uncertainty()),
+ new Options(new Count()));
+ }
+
+ public static Runnable helpPrinter()
+ {
+ return new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ printHelp();
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java
index ab489be..017b106 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java
@@ -26,23 +26,25 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import org.apache.cassandra.stress.generatedata.DataGenHexFromDistribution;
-import org.apache.cassandra.stress.generatedata.DataGenHexFromOpIndex;
-import org.apache.cassandra.stress.generatedata.DistributionFactory;
-import org.apache.cassandra.stress.generatedata.KeyGen;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.SeedGenerator;
+import org.apache.cassandra.stress.generate.SeedRandomGenerator;
+import org.apache.cassandra.stress.generate.SeedSeriesGenerator;
// Settings for key generation
public class SettingsKey implements Serializable
{
- private final int keySize;
+ final int keySize;
private final DistributionFactory distribution;
+ private final DistributionFactory clustering;
private final long[] range;
public SettingsKey(DistributionOptions options)
{
this.keySize = Integer.parseInt(options.size.value());
this.distribution = options.dist.get();
+ this.clustering = options.clustering.get();
this.range = null;
}
@@ -50,8 +52,9 @@ public class SettingsKey implements Serializable
{
this.keySize = Integer.parseInt(options.size.value());
this.distribution = null;
+ this.clustering = null;
String[] bounds = options.populate.value().split("\\.\\.+");
- this.range = new long[] { Long.parseLong(bounds[0]), Long.parseLong(bounds[1]) };
+ this.range = new long[] { OptionDistribution.parseLong(bounds[0]), OptionDistribution.parseLong(bounds[1]) };
}
// Option Declarations
@@ -59,6 +62,7 @@ public class SettingsKey implements Serializable
private static final class DistributionOptions extends GroupedOptions
{
final OptionDistribution dist;
+ final OptionDistribution clustering = new OptionDistribution("cluster=", "fixed(1)", "Keys are clustered in adjacent value runs of this size");
final OptionSimple size = new OptionSimple("size=", "[0-9]+", "10", "Key size in bytes", false);
public DistributionOptions(String defaultLimit)
@@ -69,7 +73,7 @@ public class SettingsKey implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(dist, size);
+ return Arrays.asList(dist, size, clustering);
}
}
@@ -80,7 +84,7 @@ public class SettingsKey implements Serializable
public PopulateOptions(String defaultLimit)
{
- populate = new OptionSimple("populate=", "[0-9]+\\.\\.+[0-9]+",
+ populate = new OptionSimple("populate=", "[0-9]+\\.\\.+[0-9]+[MBK]?",
"1.." + defaultLimit,
"Populate all keys in sequence", true);
}
@@ -92,12 +96,9 @@ public class SettingsKey implements Serializable
}
}
- public KeyGen newKeyGen()
+ public SeedGenerator newSeedGenerator()
{
- return new KeyGen(range == null
- ? new DataGenHexFromDistribution(distribution.get())
- : new DataGenHexFromOpIndex(range[0], range[1]),
- keySize);
+ return range == null ? new SeedRandomGenerator(distribution.get(), clustering.get()) : new SeedSeriesGenerator(range[0], range[1]);
}
// CLI Utility Methods
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java
index 8a5975f..5735f9d 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java
@@ -27,7 +27,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import org.apache.cassandra.stress.generatedata.Distribution;
+import org.apache.cassandra.stress.generate.Distribution;
public class SettingsMisc implements Serializable
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
index 95c3da3..1aa745c 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
@@ -161,8 +161,10 @@ public class SettingsMode implements Serializable
String[] params = clArgs.remove("-mode");
if (params == null)
{
- ThriftOptions opts = new ThriftOptions();
- opts.smart.accept("smart");
+ Cql3NativeOptions opts = new Cql3NativeOptions();
+ opts.accept("cql3");
+ opts.accept("native");
+ opts.accept("prepared");
return new SettingsMode(opts);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
index ffafb67..5fb2bb2 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
@@ -25,40 +25,51 @@ import java.nio.ByteBuffer;
import java.util.*;
import org.apache.cassandra.thrift.*;
+import org.apache.cassandra.thrift.ConsistencyLevel;
import org.apache.cassandra.utils.ByteBufferUtil;
public class SettingsSchema implements Serializable
{
- public static final String DEFAULT_COMPARATOR = "AsciiType";
public static final String DEFAULT_VALIDATOR = "BytesType";
private final String replicationStrategy;
private final Map<String, String> replicationStrategyOptions;
- private final IndexType indexType;
private final String compression;
private final String compactionStrategy;
private final Map<String, String> compactionStrategyOptions;
public final String keyspace;
- public SettingsSchema(Options options)
+ public SettingsSchema(Options options, SettingsCommand command)
{
+ if (command instanceof SettingsCommandUser)
+ {
+ if (options.compaction.setByUser() || options.keyspace.setByUser() || options.compression.setByUser() || options.replication.setByUser())
+ throw new IllegalArgumentException("Cannot provide command line schema settings if a user profile is provided");
+
+ keyspace = ((SettingsCommandUser) command).profile.keyspaceName;
+ }
+ else
+ keyspace = options.keyspace.value();
+
replicationStrategy = options.replication.getStrategy();
replicationStrategyOptions = options.replication.getOptions();
- if (options.index.setByUser())
- indexType = IndexType.valueOf(options.index.value().toUpperCase());
- else
- indexType = null;
compression = options.compression.value();
compactionStrategy = options.compaction.getStrategy();
compactionStrategyOptions = options.compaction.getOptions();
- keyspace = options.keyspace.value();
}
public void createKeySpaces(StressSettings settings)
{
- createKeySpacesThrift(settings);
+ if (!(settings.command instanceof SettingsCommandUser))
+ {
+ createKeySpacesThrift(settings);
+ }
+ else
+ {
+ ((SettingsCommandUser) settings.command).profile.maybeCreateSchema(settings);
+ }
}
@@ -71,7 +82,7 @@ public class SettingsSchema implements Serializable
// column family for standard columns
CfDef standardCfDef = new CfDef(keyspace, "Standard1");
- Map<String, String> compressionOptions = new HashMap<String, String>();
+ Map<String, String> compressionOptions = new HashMap<>();
if (compression != null)
compressionOptions.put("sstable_compression", compression);
@@ -80,28 +91,8 @@ public class SettingsSchema implements Serializable
.setDefault_validation_class(DEFAULT_VALIDATOR)
.setCompression_options(compressionOptions);
- if (!settings.columns.useTimeUUIDComparator)
- {
- for (int i = 0; i < settings.columns.maxColumnsPerKey; i++)
- {
- standardCfDef.addToColumn_metadata(new ColumnDef(ByteBufferUtil.bytes("C" + i), "BytesType"));
- }
- }
-
- if (indexType != null)
- {
- ColumnDef standardColumn = new ColumnDef(ByteBufferUtil.bytes("C1"), "BytesType");
- standardColumn.setIndex_type(indexType).setIndex_name("Idx1");
- standardCfDef.setColumn_metadata(Arrays.asList(standardColumn));
- }
-
- // column family with super columns
- CfDef superCfDef = new CfDef(keyspace, "Super1")
- .setColumn_type("Super");
- superCfDef.setComparator_type(DEFAULT_COMPARATOR)
- .setSubcomparator_type(comparator)
- .setDefault_validation_class(DEFAULT_VALIDATOR)
- .setCompression_options(compressionOptions);
+ for (int i = 0; i < settings.columns.names.size(); i++)
+ standardCfDef.addToColumn_metadata(new ColumnDef(settings.columns.names.get(i), "BytesType"));
// column family for standard counters
CfDef counterCfDef = new CfDef(keyspace, "Counter1")
@@ -109,13 +100,6 @@ public class SettingsSchema implements Serializable
.setDefault_validation_class("CounterColumnType")
.setCompression_options(compressionOptions);
- // column family with counter super columns
- CfDef counterSuperCfDef = new CfDef(keyspace, "SuperCounter1")
- .setComparator_type(comparator)
- .setDefault_validation_class("CounterColumnType")
- .setColumn_type("Super")
- .setCompression_options(compressionOptions);
-
ksdef.setName(keyspace);
ksdef.setStrategy_class(replicationStrategy);
@@ -127,19 +111,15 @@ public class SettingsSchema implements Serializable
if (compactionStrategy != null)
{
standardCfDef.setCompaction_strategy(compactionStrategy);
- superCfDef.setCompaction_strategy(compactionStrategy);
counterCfDef.setCompaction_strategy(compactionStrategy);
- counterSuperCfDef.setCompaction_strategy(compactionStrategy);
if (!compactionStrategyOptions.isEmpty())
{
standardCfDef.setCompaction_strategy_options(compactionStrategyOptions);
- superCfDef.setCompaction_strategy_options(compactionStrategyOptions);
counterCfDef.setCompaction_strategy_options(compactionStrategyOptions);
- counterSuperCfDef.setCompaction_strategy_options(compactionStrategyOptions);
}
}
- ksdef.setCf_defs(new ArrayList<>(Arrays.asList(standardCfDef, superCfDef, counterCfDef, counterSuperCfDef)));
+ ksdef.setCf_defs(new ArrayList<>(Arrays.asList(standardCfDef, counterCfDef)));
Cassandra.Client client = settings.getRawThriftClient(false);
@@ -191,24 +171,23 @@ public class SettingsSchema implements Serializable
{
final OptionReplication replication = new OptionReplication();
final OptionCompaction compaction = new OptionCompaction();
- final OptionSimple index = new OptionSimple("index=", "KEYS|CUSTOM|COMPOSITES", null, "Type of index to create on needed column families (KEYS)", false);
final OptionSimple keyspace = new OptionSimple("keyspace=", ".*", "Keyspace1", "The keyspace name to use", false);
final OptionSimple compression = new OptionSimple("compression=", ".*", null, "Specify the compression to use for sstable, default:no compression", false);
@Override
public List<? extends Option> options()
{
- return Arrays.asList(replication, index, keyspace, compaction, compression);
+ return Arrays.asList(replication, keyspace, compaction, compression);
}
}
// CLI Utility Methods
- public static SettingsSchema get(Map<String, String[]> clArgs)
+ public static SettingsSchema get(Map<String, String[]> clArgs, SettingsCommand command)
{
String[] params = clArgs.remove("-schema");
if (params == null)
- return new SettingsSchema(new Options());
+ return new SettingsSchema(new Options(), command);
GroupedOptions options = GroupedOptions.select(params, new Options());
if (options == null)
@@ -217,7 +196,7 @@ public class SettingsSchema implements Serializable
System.out.println("Invalid -schema options provided, see output for valid options");
System.exit(1);
}
- return new SettingsSchema((Options) options);
+ return new SettingsSchema((Options) options, command);
}
public static void printHelp()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
index 396095d..8b0ef6a 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
@@ -111,7 +111,7 @@ public class SettingsTransport implements Serializable
// Option Declarations
- static class TOptions extends GroupedOptions
+ static class TOptions extends GroupedOptions implements Serializable
{
final OptionSimple factory = new OptionSimple("factory=", ".*", TFramedTransportFactory.class.getName(), "Fully-qualified ITransportFactory class name for creating a connection. Note: For Thrift over SSL, use org.apache.cassandra.thrift.SSLTransportFactory.", false);
final OptionSimple trustStore = new OptionSimple("truststore=", ".*", null, "SSL: full path to truststore", false);
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
index a1d68b4..ab57289 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
@@ -29,6 +29,7 @@ import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.stress.util.JavaDriverClient;
import org.apache.cassandra.stress.util.SimpleThriftClient;
import org.apache.cassandra.stress.util.SmartThriftClient;
+import org.apache.cassandra.stress.util.ThriftClient;
import org.apache.cassandra.thrift.Cassandra;
import org.apache.cassandra.thrift.InvalidRequestException;
import org.apache.cassandra.transport.SimpleClient;
@@ -37,7 +38,6 @@ import org.apache.thrift.transport.TTransport;
public class StressSettings implements Serializable
{
-
public final SettingsCommand command;
public final SettingsRate rate;
public final SettingsKey keys;
@@ -65,7 +65,24 @@ public class StressSettings implements Serializable
this.sendToDaemon = sendToDaemon;
}
- public SmartThriftClient getSmartThriftClient()
+ private SmartThriftClient tclient;
+
+ /**
+ * Thrift client connection
+ * @return cassandra client connection
+ */
+ public synchronized ThriftClient getThriftClient()
+ {
+ if (mode.api != ConnectionAPI.THRIFT_SMART)
+ return getSimpleThriftClient();
+
+ if (tclient == null)
+ tclient = getSmartThriftClient();
+
+ return tclient;
+ }
+
+ private SmartThriftClient getSmartThriftClient()
{
Metadata metadata = getJavaDriverClient().getCluster().getMetadata();
return new SmartThriftClient(this, schema.keyspace, metadata);
@@ -75,7 +92,7 @@ public class StressSettings implements Serializable
* Thrift client connection
* @return cassandra client connection
*/
- public SimpleThriftClient getThriftClient()
+ private SimpleThriftClient getSimpleThriftClient()
{
return new SimpleThriftClient(getRawThriftClient(node.randomNode(), true));
}
@@ -139,6 +156,11 @@ public class StressSettings implements Serializable
public JavaDriverClient getJavaDriverClient()
{
+ return getJavaDriverClient(true);
+ }
+
+ public JavaDriverClient getJavaDriverClient(boolean setKeyspace)
+ {
if (client != null)
return client;
@@ -153,7 +175,9 @@ public class StressSettings implements Serializable
EncryptionOptions.ClientEncryptionOptions encOptions = transport.getEncryptionOptions();
JavaDriverClient c = new JavaDriverClient(currentNode, port.nativePort, encOptions);
c.connect(mode.compression());
- c.execute("USE \"" + schema.keyspace + "\";", org.apache.cassandra.db.ConsistencyLevel.ONE);
+ if (setKeyspace)
+ c.execute("USE \"" + schema.keyspace + "\";", org.apache.cassandra.db.ConsistencyLevel.ONE);
+
return client = c;
}
}
@@ -165,7 +189,7 @@ public class StressSettings implements Serializable
public void maybeCreateKeyspaces()
{
- if (command.type == Command.WRITE || command.type == Command.COUNTER_WRITE)
+ if (command.type == Command.WRITE || command.type == Command.COUNTER_WRITE || command.type == Command.USER)
schema.createKeySpaces(this);
}
@@ -202,7 +226,7 @@ public class StressSettings implements Serializable
SettingsLog log = SettingsLog.get(clArgs);
SettingsMode mode = SettingsMode.get(clArgs);
SettingsNode node = SettingsNode.get(clArgs);
- SettingsSchema schema = SettingsSchema.get(clArgs);
+ SettingsSchema schema = SettingsSchema.get(clArgs, command);
SettingsTransport transport = SettingsTransport.get(clArgs);
if (!clArgs.isEmpty())
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/ValidationType.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/ValidationType.java b/tools/stress/src/org/apache/cassandra/stress/settings/ValidationType.java
new file mode 100644
index 0000000..c22242d
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/ValidationType.java
@@ -0,0 +1,8 @@
+package org.apache.cassandra.stress.settings;
+
+public enum ValidationType
+{
+
+ NOT_FAIL, NON_ZERO, SUBSET, EQUAL
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java b/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java
index f216c05..c901461 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java
@@ -18,6 +18,8 @@
package org.apache.cassandra.stress.util;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import javax.net.ssl.SSLContext;
import com.datastax.driver.core.*;
@@ -40,6 +42,8 @@ public class JavaDriverClient
private Cluster cluster;
private Session session;
+ private static final ConcurrentMap<String, PreparedStatement> stmts = new ConcurrentHashMap<>();
+
public JavaDriverClient(String host, int port)
{
this(host, port, new EncryptionOptions.ClientEncryptionOptions());
@@ -54,7 +58,18 @@ public class JavaDriverClient
public PreparedStatement prepare(String query)
{
- return getSession().prepare(query);
+ PreparedStatement stmt = stmts.get(query);
+ if (stmt != null)
+ return stmt;
+ synchronized (stmts)
+ {
+ stmt = stmts.get(query);
+ if (stmt != null)
+ return stmt;
+ stmt = getSession().prepare(query);
+ stmts.put(query, stmt);
+ }
+ return stmt;
}
public void connect(ProtocolOptions.Compression compression) throws Exception
@@ -116,7 +131,7 @@ public class JavaDriverClient
* @param cl
* @return
*/
- ConsistencyLevel from(org.apache.cassandra.db.ConsistencyLevel cl)
+ public static ConsistencyLevel from(org.apache.cassandra.db.ConsistencyLevel cl)
{
switch (cl)
{
[18/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionOffsetApache.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionOffsetApache.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionOffsetApache.java
deleted file mode 100644
index cfbc385..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionOffsetApache.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import org.apache.commons.math3.distribution.AbstractRealDistribution;
-
-public class DistributionOffsetApache extends Distribution
-{
-
- final AbstractRealDistribution delegate;
- final long min, delta;
-
- public DistributionOffsetApache(AbstractRealDistribution delegate, long min, long max)
- {
- this.delegate = delegate;
- this.min = min;
- this.delta = max - min;
- }
-
- @Override
- public long next()
- {
- return offset(min, delta, delegate.sample());
- }
-
- @Override
- public long inverseCumProb(double cumProb)
- {
- return offset(min, delta, delegate.inverseCumulativeProbability(cumProb));
- }
-
- private long offset(long min, long delta, double val)
- {
- long r = (long) val;
- if (r < 0)
- r = 0;
- if (r > delta)
- r = delta;
- return min + r;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionSeqBatch.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionSeqBatch.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionSeqBatch.java
deleted file mode 100644
index 8e1a5d5..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionSeqBatch.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-public class DistributionSeqBatch extends DataGenHex
-{
-
- final Distribution delegate;
- final int batchSize;
- final long maxKey;
-
- private int batchIndex;
- private long batchKey;
-
- // object must be published safely if passed between threadCount, due to batchIndex not being volatile. various
- // hacks possible, but not ideal. don't want to use volatile as object intended for single threaded use.
- public DistributionSeqBatch(int batchSize, long maxKey, Distribution delegate)
- {
- this.batchIndex = batchSize;
- this.batchSize = batchSize;
- this.maxKey = maxKey;
- this.delegate = delegate;
- }
-
- @Override
- long next(long operationIndex)
- {
- if (batchIndex >= batchSize)
- {
- batchKey = delegate.next();
- batchIndex = 0;
- }
- long r = batchKey + batchIndex++;
- if (r > maxKey)
- {
- batchKey = delegate.next();
- batchIndex = 1;
- r = batchKey;
- }
- return r;
- }
-
- @Override
- public boolean isDeterministic()
- {
- return false;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/KeyGen.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/KeyGen.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/KeyGen.java
deleted file mode 100644
index dad5918..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/KeyGen.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-
-public class KeyGen
-{
-
- final DataGen dataGen;
- final int keySize;
- final List<ByteBuffer> keyBuffers = new ArrayList<>();
-
- public KeyGen(DataGen dataGen, int keySize)
- {
- this.dataGen = dataGen;
- this.keySize = keySize;
- }
-
- public List<ByteBuffer> getKeys(int n, long index)
- {
- while (keyBuffers.size() < n)
- keyBuffers.add(ByteBuffer.wrap(new byte[keySize]));
- dataGen.generate(keyBuffers, index, null);
- return keyBuffers;
- }
-
- public boolean isDeterministic()
- {
- return dataGen.isDeterministic();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java
deleted file mode 100644
index 9c6ca43..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.List;
-
-/**
- * Generates a row of data, by constructing one byte buffers per column according to some algorithm
- * and delegating the work of populating the values of those byte buffers to the provided data generator
- */
-public abstract class RowGen
-{
-
- final DataGen dataGen;
- protected RowGen(DataGen dataGenerator)
- {
- this.dataGen = dataGenerator;
- }
-
- public List<ByteBuffer> generate(long operationIndex, ByteBuffer key)
- {
- List<ByteBuffer> fill = getColumns(operationIndex);
- dataGen.generate(fill, operationIndex, key);
- return fill;
- }
-
- // these byte[] may be re-used
- abstract List<ByteBuffer> getColumns(long operationIndex);
- abstract public int count(long operationIndex);
-
- abstract public boolean isDeterministic();
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java
deleted file mode 100644
index fffad2f..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-public class RowGenDistributedSize extends RowGen
-{
-
- // TODO - make configurable
- static final int MAX_SINGLE_CACHE_SIZE = 16 * 1024;
-
- final Distribution countDistribution;
- final Distribution sizeDistribution;
-
- final TreeMap<Integer, ByteBuffer> cache = new TreeMap<>();
-
- // array re-used for returning columns
- final ByteBuffer[] ret;
- final int[] sizes;
-
- final boolean isDeterministic;
-
- public RowGenDistributedSize(DataGen dataGenerator, Distribution countDistribution, Distribution sizeDistribution)
- {
- super(dataGenerator);
- this.countDistribution = countDistribution;
- 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();
- }
-
- ByteBuffer getBuffer(int size)
- {
- if (size >= MAX_SINGLE_CACHE_SIZE)
- return ByteBuffer.allocate(size);
- Map.Entry<Integer, ByteBuffer> found = cache.ceilingEntry(size);
- if (found == null)
- {
- // remove the next entry down, and replace it with a cache of this size
- Integer del = cache.lowerKey(size);
- if (del != null)
- cache.remove(del);
- return ByteBuffer.allocate(size);
- }
- ByteBuffer r = found.getValue();
- cache.remove(found.getKey());
- return r;
- }
-
- @Override
- List<ByteBuffer> getColumns(long operationIndex)
- {
- int i = 0;
- int count = (int) countDistribution.next();
- while (i < count)
- {
- int columnSize = (int) sizeDistribution.next();
- sizes[i] = columnSize;
- ret[i] = getBuffer(columnSize);
- i++;
- }
- while (i < ret.length && ret[i] != null)
- ret[i] = null;
- i = 0;
- while (i < count)
- {
- ByteBuffer b = ret[i];
- cache.put(b.capacity(), b);
- b.position(b.capacity() - sizes[i]);
- ret[i] = b.slice();
- b.position(0);
- i++;
- }
- return Arrays.asList(ret).subList(0, count);
- }
-
- public int count(long operationIndex)
- {
- return (int) countDistribution.next();
- }
-
- @Override
- public boolean isDeterministic()
- {
- return isDeterministic;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java
deleted file mode 100644
index 9a8c37d..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-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<Integer>
-{
- public CqlCounterAdder(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected String buildQuery()
- {
- String counterCF = state.isCql2() ? state.type.table : "Counter3";
-
- StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(counterCF));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- query.append(" SET ");
-
- // TODO : increment distribution subset of columns
- for (int i = 0; i < state.settings.columns.maxColumnsPerKey; i++)
- {
- if (i > 0)
- query.append(",");
-
- query.append('C').append(i).append("=C").append(i).append("+?");
- }
- query.append(" WHERE KEY=?");
- return query.toString();
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- final List<Object> 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<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new CqlRunOpAlwaysSucceed(client, query, queryId, params, keyid, key, 1);
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java
deleted file mode 100644
index 88d622e..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.List;
-
-public class CqlCounterGetter extends CqlOperation<Integer>
-{
-
- public CqlCounterGetter(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- return Collections.<Object>singletonList(ByteBuffer.wrap(key));
- }
-
- @Override
- protected String buildQuery()
- {
- 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() ? state.type.table : "Counter3";
-
- query.append(" FROM ").append(wrapInQuotesIfRequired(counterCF));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- return query.append(" WHERE KEY=?").toString();
- }
-
- @Override
- protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new CqlRunOpTestNonEmpty(client, query, queryId, params, keyid, key);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java
deleted file mode 100644
index 046381e..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
-*
-* 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.
-*
-*/
-
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.cassandra.utils.FBUtilities;
-
-public class CqlIndexedRangeSlicer extends CqlOperation<byte[][]>
-{
-
- volatile boolean acceptNoResults = false;
-
- public CqlIndexedRangeSlicer(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected String buildQuery()
- {
- StringBuilder query = new StringBuilder("SELECT");
- query.append(wrapInQuotesIfRequired("key"));
- query.append(" FROM ");
- query.append(wrapInQuotesIfRequired(state.type.table));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- final String columnName = (state.settings.columns.namestrs.get(1));
- query.append(" WHERE ").append(columnName).append("=?")
- .append(" AND KEY > ? LIMIT ").append(state.settings.command.keysAtOnce);
- return query.toString();
- }
-
- @Override
- protected void run(CqlOperation.ClientWrapper client) throws IOException
- {
- acceptNoResults = false;
- final List<ByteBuffer> columns = generateColumnValues(getKey());
- final ByteBuffer value = columns.get(1); // only C1 column is indexed
- byte[] minKey = new byte[0];
- int rowCount;
- do
- {
- List<Object> params = Arrays.<Object>asList(value, ByteBuffer.wrap(minKey));
- CqlRunOp<byte[][]> op = run(client, params, value, new String(value.array()));
- byte[][] keys = op.result;
- rowCount = keys.length;
- minKey = getNextMinKey(minKey, keys);
- acceptNoResults = true;
- } while (rowCount > 0);
- }
-
- private final class IndexedRangeSliceRunOp extends CqlRunOpFetchKeys
- {
-
- protected IndexedRangeSliceRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- super(client, query, queryId, params, keyid, key);
- }
-
- @Override
- public boolean validate(byte[][] result)
- {
- return acceptNoResults || result.length > 0;
- }
- }
-
- @Override
- protected CqlRunOp<byte[][]> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new IndexedRangeSliceRunOp(client, query, queryId, params, keyid, key);
- }
-
- private static byte[] getNextMinKey(byte[] cur, byte[][] keys)
- {
- // find max
- for (byte[] key : keys)
- if (FBUtilities.compareUnsigned(cur, key) < 0)
- cur = key;
-
- // increment
- for (int i = 0 ; i < cur.length ; i++)
- if (++cur[i] != 0)
- break;
- return cur;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java
deleted file mode 100644
index 71cdadf..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.cassandra.utils.UUIDGen;
-
-public class CqlInserter extends CqlOperation<Integer>
-{
-
- 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.type.table));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- query.append(" SET ");
-
- for (int i = 0 ; i < state.settings.columns.maxColumnsPerKey; i++)
- {
- if (i > 0)
- query.append(',');
-
- if (state.settings.columns.useTimeUUIDComparator)
- {
- if (state.isCql3())
- throw new UnsupportedOperationException("Cannot use UUIDs in column names with CQL3");
-
- query.append(wrapInQuotesIfRequired(UUIDGen.getTimeUUID().toString()))
- .append(" = ?");
- }
- else
- {
- query.append(wrapInQuotesIfRequired("C" + i)).append(" = ?");
- }
- }
-
- query.append(" WHERE KEY=?");
- return query.toString();
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- final ArrayList<Object> queryParams = new ArrayList<>();
- final List<ByteBuffer> values = generateColumnValues(ByteBuffer.wrap(key));
- queryParams.addAll(values);
- queryParams.add(ByteBuffer.wrap(key));
- return queryParams;
- }
-
- @Override
- protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new CqlRunOpAlwaysSucceed(client, query, queryId, params, keyid, key, 1);
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlMultiGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlMultiGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlMultiGetter.java
deleted file mode 100644
index 80a7118..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlMultiGetter.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.IOException;
-
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.util.ThriftClient;
-
-public class CqlMultiGetter extends Operation
-{
- public CqlMultiGetter(State state, long idx)
- {
- super(state, idx);
- throw new RuntimeException("Multiget is not implemented for CQL");
- }
-
- @Override
- public void run(ThriftClient client) throws IOException
- {
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java
deleted file mode 100644
index 1c59e2d..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import com.datastax.driver.core.PreparedStatement;
-import com.datastax.driver.core.ResultSet;
-import com.datastax.driver.core.Row;
-import com.google.common.base.Function;
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.settings.ConnectionStyle;
-import org.apache.cassandra.stress.settings.CqlVersion;
-import org.apache.cassandra.stress.util.JavaDriverClient;
-import org.apache.cassandra.stress.util.ThriftClient;
-import org.apache.cassandra.thrift.Compression;
-import org.apache.cassandra.thrift.CqlResult;
-import org.apache.cassandra.thrift.CqlRow;
-import org.apache.cassandra.thrift.ThriftConversion;
-import org.apache.cassandra.transport.SimpleClient;
-import org.apache.cassandra.transport.messages.ResultMessage;
-import org.apache.cassandra.utils.ByteBufferUtil;
-import org.apache.thrift.TException;
-
-public abstract class CqlOperation<V> extends Operation
-{
-
- protected abstract List<Object> getQueryParameters(byte[] key);
- protected abstract String buildQuery();
- protected abstract CqlRunOp<V> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String id, ByteBuffer key);
-
- public CqlOperation(State state, long idx)
- {
- super(state, idx);
- if (state.settings.columns.useSuperColumns)
- 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<V> run(final ClientWrapper client, final List<Object> queryParams, final ByteBuffer key, final String keyid) throws IOException
- {
- final CqlRunOp<V> op;
- if (state.settings.mode.style == ConnectionStyle.CQL_PREPARED)
- {
- final Object id;
- Object idobj = state.getCqlCache();
- if (idobj == null)
- {
- try
- {
- id = client.createPreparedStatement(buildQuery());
- } catch (TException e)
- {
- throw new RuntimeException(e);
- }
- state.storeCqlCache(id);
- }
- else
- id = idobj;
-
- op = buildRunOp(client, null, id, queryParams, keyid, key);
- }
- else
- {
- final String query;
- Object qobj = state.getCqlCache();
- if (qobj == null)
- state.storeCqlCache(query = buildQuery());
- else
- query = qobj.toString();
-
- op = buildRunOp(client, query, null, queryParams, keyid, key);
- }
-
- timeWithRetry(op);
- return op;
- }
-
- protected void run(final ClientWrapper client) throws IOException
- {
- final byte[] key = getKey().array();
- final List<Object> queryParams = getQueryParameters(key);
- run(client, queryParams, ByteBuffer.wrap(key), new String(key));
- }
-
- // Classes to process Cql results
-
- // Always succeeds so long as the query executes without error; provides a keyCount to increment on instantiation
- protected final class CqlRunOpAlwaysSucceed extends CqlRunOp<Integer>
- {
-
- final int keyCount;
-
- protected CqlRunOpAlwaysSucceed(ClientWrapper client, String query, Object queryId, List<Object> params, String id, ByteBuffer key, int keyCount)
- {
- super(client, query, queryId, RowCountHandler.INSTANCE, params, id, key);
- this.keyCount = keyCount;
- }
-
- @Override
- public boolean validate(Integer result)
- {
- return true;
- }
-
- @Override
- public int keyCount()
- {
- return keyCount;
- }
- }
-
- // Succeeds so long as the result set is nonempty, and the query executes without error
- protected final class CqlRunOpTestNonEmpty extends CqlRunOp<Integer>
- {
-
- protected CqlRunOpTestNonEmpty(ClientWrapper client, String query, Object queryId, List<Object> params, String id, ByteBuffer key)
- {
- super(client, query, queryId, RowCountHandler.INSTANCE, params, id, key);
- }
-
- @Override
- public boolean validate(Integer result)
- {
- return result > 0;
- }
-
- @Override
- public int keyCount()
- {
- return result;
- }
- }
-
- // Requires a custom validate() method, but fetches and stores the keys from the result set for further processing
- protected abstract class CqlRunOpFetchKeys extends CqlRunOp<byte[][]>
- {
-
- protected CqlRunOpFetchKeys(ClientWrapper client, String query, Object queryId, List<Object> params, String id, ByteBuffer key)
- {
- super(client, query, queryId, KeysHandler.INSTANCE, params, id, key);
- }
-
- @Override
- public int keyCount()
- {
- return result.length;
- }
-
- }
-
- protected final class CqlRunOpMatchResults extends CqlRunOp<ByteBuffer[][]>
- {
-
- final List<List<ByteBuffer>> 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<Object> params, String id, ByteBuffer key, List<List<ByteBuffer>> expect)
- {
- super(client, query, queryId, RowsHandler.INSTANCE, params, id, key);
- this.expect = expect;
- }
-
- @Override
- public int keyCount()
- {
- return result == null ? 0 : result.length;
- }
-
- public boolean validate(ByteBuffer[][] result)
- {
- if (result.length != expect.size())
- return false;
- for (int i = 0 ; i < result.length ; i++)
- if (expect.get(i) != null && !expect.get(i).equals(Arrays.asList(result[i])))
- return false;
- return true;
- }
- }
-
- // Cql
- protected abstract class CqlRunOp<V> implements RunOp
- {
-
- final ClientWrapper client;
- final String query;
- final Object queryId;
- final List<Object> params;
- final String id;
- final ByteBuffer key;
- final ResultHandler<V> handler;
- V result;
-
- private CqlRunOp(ClientWrapper client, String query, Object queryId, ResultHandler<V> handler, List<Object> params, String id, ByteBuffer key)
- {
- this.client = client;
- this.query = query;
- this.queryId = queryId;
- this.handler = handler;
- this.params = params;
- this.id = id;
- this.key = key;
- }
-
- @Override
- public boolean run() throws Exception
- {
- return queryId != null
- ? validate(result = client.execute(queryId, key, params, handler))
- : validate(result = client.execute(query, key, params, handler));
- }
-
- @Override
- public String key()
- {
- return id;
- }
-
- public abstract boolean validate(V result);
-
- }
-
-
- /// LOTS OF WRAPPING/UNWRAPPING NONSENSE
-
-
- @Override
- public void run(final ThriftClient client) throws IOException
- {
- run(wrap(client));
- }
-
- @Override
- public void run(SimpleClient client) throws IOException
- {
- run(wrap(client));
- }
-
- @Override
- public void run(JavaDriverClient client) throws IOException
- {
- run(wrap(client));
- }
-
- public ClientWrapper wrap(ThriftClient client)
- {
- return state.isCql3()
- ? new Cql3CassandraClientWrapper(client)
- : new Cql2CassandraClientWrapper(client);
-
- }
-
- public ClientWrapper wrap(JavaDriverClient client)
- {
- return new JavaDriverWrapper(client);
- }
-
- public ClientWrapper wrap(SimpleClient client)
- {
- return new SimpleClientWrapper(client);
- }
-
- protected interface ClientWrapper
- {
- Object createPreparedStatement(String cqlQuery) throws TException;
- <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
- <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
- }
-
- private final class JavaDriverWrapper implements ClientWrapper
- {
- final JavaDriverClient client;
- private JavaDriverWrapper(JavaDriverClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
- {
- String formattedQuery = formatCqlQuery(query, queryParams, state.isCql3());
- return handler.javaDriverHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(state.settings.command.consistencyLevel)));
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
- {
- return handler.javaDriverHandler().apply(
- client.executePrepared(
- (PreparedStatement) preparedStatementId,
- queryParams,
- ThriftConversion.fromThrift(state.settings.command.consistencyLevel)));
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery)
- {
- return client.prepare(cqlQuery);
- }
- }
-
- private final class SimpleClientWrapper implements ClientWrapper
- {
- final SimpleClient client;
- private SimpleClientWrapper(SimpleClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
- {
- String formattedQuery = formatCqlQuery(query, queryParams, state.isCql3());
- return handler.thriftHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(state.settings.command.consistencyLevel)));
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
- {
- return handler.thriftHandler().apply(
- client.executePrepared(
- (byte[]) preparedStatementId,
- toByteBufferParams(queryParams),
- ThriftConversion.fromThrift(state.settings.command.consistencyLevel)));
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery)
- {
- return client.prepare(cqlQuery).statementId.bytes;
- }
- }
-
- // client wrapper for Cql3
- private final class Cql3CassandraClientWrapper implements ClientWrapper
- {
- final ThriftClient client;
- private Cql3CassandraClientWrapper(ThriftClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- String formattedQuery = formatCqlQuery(query, queryParams, true);
- return handler.simpleNativeHandler().apply(
- client.execute_cql3_query(formattedQuery, key, Compression.NONE, state.settings.command.consistencyLevel)
- );
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- Integer id = (Integer) preparedStatementId;
- return handler.simpleNativeHandler().apply(
- client.execute_prepared_cql3_query(id, key, toByteBufferParams(queryParams), state.settings.command.consistencyLevel)
- );
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery) throws TException
- {
- return client.prepare_cql3_query(cqlQuery, Compression.NONE);
- }
- }
-
- // client wrapper for Cql2
- private final class Cql2CassandraClientWrapper implements ClientWrapper
- {
- final ThriftClient client;
- private Cql2CassandraClientWrapper(ThriftClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- String formattedQuery = formatCqlQuery(query, queryParams, false);
- return handler.simpleNativeHandler().apply(
- client.execute_cql_query(formattedQuery, key, Compression.NONE)
- );
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- Integer id = (Integer) preparedStatementId;
- return handler.simpleNativeHandler().apply(
- client.execute_prepared_cql_query(id, key, toByteBufferParams(queryParams))
- );
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery) throws TException
- {
- return client.prepare_cql_query(cqlQuery, Compression.NONE);
- }
- }
-
- // interface for building functions to standardise results from each client
- protected static interface ResultHandler<V>
- {
- Function<ResultSet, V> javaDriverHandler();
- Function<ResultMessage, V> thriftHandler();
- Function<CqlResult, V> simpleNativeHandler();
- }
-
- protected static class RowCountHandler implements ResultHandler<Integer>
- {
- static final RowCountHandler INSTANCE = new RowCountHandler();
-
- @Override
- public Function<ResultSet, Integer> javaDriverHandler()
- {
- return new Function<ResultSet, Integer>()
- {
- @Override
- public Integer apply(ResultSet rows)
- {
- if (rows == null)
- return 0;
- return rows.all().size();
- }
- };
- }
-
- @Override
- public Function<ResultMessage, Integer> thriftHandler()
- {
- return new Function<ResultMessage, Integer>()
- {
- @Override
- public Integer apply(ResultMessage result)
- {
- return result instanceof ResultMessage.Rows ? ((ResultMessage.Rows) result).result.size() : 0;
- }
- };
- }
-
- @Override
- public Function<CqlResult, Integer> simpleNativeHandler()
- {
- return new Function<CqlResult, Integer>()
- {
-
- @Override
- public Integer apply(CqlResult result)
- {
- switch (result.getType())
- {
- case ROWS:
- return result.getRows().size();
- default:
- return 1;
- }
- }
- };
- }
-
- }
-
- // Processes results from each client into an array of all key bytes returned
- protected static final class RowsHandler implements ResultHandler<ByteBuffer[][]>
- {
- static final RowsHandler INSTANCE = new RowsHandler();
-
- @Override
- public Function<ResultSet, ByteBuffer[][]> javaDriverHandler()
- {
- return new Function<ResultSet, ByteBuffer[][]>()
- {
-
- @Override
- public ByteBuffer[][] apply(ResultSet result)
- {
- if (result == null)
- return new ByteBuffer[0][];
- List<Row> rows = result.all();
-
- ByteBuffer[][] r = new ByteBuffer[rows.size()][];
- for (int i = 0 ; i < r.length ; i++)
- {
- Row row = rows.get(i);
- r[i] = new ByteBuffer[row.getColumnDefinitions().size()];
- for (int j = 0 ; j < row.getColumnDefinitions().size() ; j++)
- r[i][j] = row.getBytes(j);
- }
- return r;
- }
- };
- }
-
- @Override
- public Function<ResultMessage, ByteBuffer[][]> thriftHandler()
- {
- return new Function<ResultMessage, ByteBuffer[][]>()
- {
-
- @Override
- public ByteBuffer[][] apply(ResultMessage result)
- {
- if (!(result instanceof ResultMessage.Rows))
- return new ByteBuffer[0][];
-
- ResultMessage.Rows rows = ((ResultMessage.Rows) result);
- ByteBuffer[][] r = new ByteBuffer[rows.result.size()][];
- for (int i = 0 ; i < r.length ; i++)
- {
- List<ByteBuffer> row = rows.result.rows.get(i);
- r[i] = new ByteBuffer[row.size()];
- for (int j = 0 ; j < row.size() ; j++)
- r[i][j] = row.get(j);
- }
- return r;
- }
- };
- }
-
- @Override
- public Function<CqlResult, ByteBuffer[][]> simpleNativeHandler()
- {
- return new Function<CqlResult, ByteBuffer[][]>()
- {
-
- @Override
- public ByteBuffer[][] apply(CqlResult result)
- {
- ByteBuffer[][] r = new ByteBuffer[result.getRows().size()][];
- for (int i = 0 ; i < r.length ; i++)
- {
- CqlRow row = result.getRows().get(i);
- r[i] = new ByteBuffer[row.getColumns().size()];
- for (int j = 0 ; j < r[i].length ; j++)
- r[i][j] = ByteBuffer.wrap(row.getColumns().get(j).getValue());
- }
- return r;
- }
- };
- }
-
- }
- // Processes results from each client into an array of all key bytes returned
- protected static final class KeysHandler implements ResultHandler<byte[][]>
- {
- static final KeysHandler INSTANCE = new KeysHandler();
-
- @Override
- public Function<ResultSet, byte[][]> javaDriverHandler()
- {
- return new Function<ResultSet, byte[][]>()
- {
-
- @Override
- public byte[][] apply(ResultSet result)
- {
-
- if (result == null)
- return new byte[0][];
- List<Row> rows = result.all();
- byte[][] r = new byte[rows.size()][];
- for (int i = 0 ; i < r.length ; i++)
- r[i] = rows.get(i).getBytes(0).array();
- return r;
- }
- };
- }
-
- @Override
- public Function<ResultMessage, byte[][]> thriftHandler()
- {
- return new Function<ResultMessage, byte[][]>()
- {
-
- @Override
- public byte[][] apply(ResultMessage result)
- {
- if (result instanceof ResultMessage.Rows)
- {
- ResultMessage.Rows rows = ((ResultMessage.Rows) result);
- byte[][] r = new byte[rows.result.size()][];
- for (int i = 0 ; i < r.length ; i++)
- r[i] = rows.result.rows.get(i).get(0).array();
- return r;
- }
- return null;
- }
- };
- }
-
- @Override
- public Function<CqlResult, byte[][]> simpleNativeHandler()
- {
- return new Function<CqlResult, byte[][]>()
- {
-
- @Override
- public byte[][] apply(CqlResult result)
- {
- byte[][] r = new byte[result.getRows().size()][];
- for (int i = 0 ; i < r.length ; i++)
- r[i] = result.getRows().get(i).getKey();
- return r;
- }
- };
- }
-
- }
-
- private static String getUnQuotedCqlBlob(ByteBuffer term, boolean isCQL3)
- {
- return isCQL3
- ? "0x" + ByteBufferUtil.bytesToHex(term)
- : ByteBufferUtil.bytesToHex(term);
- }
-
- /**
- * Constructs a CQL query string by replacing instances of the character
- * '?', with the corresponding parameter.
- *
- * @param query base query string to format
- * @param parms sequence of string query parameters
- * @return formatted CQL query string
- */
- private static String formatCqlQuery(String query, List<Object> parms, boolean isCql3)
- {
- int marker, position = 0;
- StringBuilder result = new StringBuilder();
-
- if (-1 == (marker = query.indexOf('?')) || parms.size() == 0)
- return query;
-
- for (Object parm : parms)
- {
- result.append(query.substring(position, marker));
- 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)))
- break;
- }
-
- if (position < query.length())
- result.append(query.substring(position));
-
- return result.toString();
- }
-
- private static List<ByteBuffer> toByteBufferParams(List<Object> params)
- {
- List<ByteBuffer> 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
- ? "\"" + string + "\""
- : string;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java
deleted file mode 100644
index 16cdff3..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.List;
-
-public class CqlRangeSlicer extends CqlOperation<Integer>
-{
- public CqlRangeSlicer(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- return Collections.<Object>singletonList(ByteBuffer.wrap(key));
- }
-
- @Override
- protected String buildQuery()
- {
- StringBuilder query = new StringBuilder("SELECT FIRST ").append(state.settings.columns.maxColumnsPerKey)
- .append(" ''..'' FROM ").append(wrapInQuotesIfRequired(state.type.table));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- return query.append(" WHERE KEY > ?").toString();
- }
-
- @Override
- protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new CqlRunOpTestNonEmpty(client, query, queryId, params, keyid, key);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java
deleted file mode 100644
index fb07edc..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.cassandra.utils.ByteBufferUtil;
-
-public class CqlReader extends CqlOperation<ByteBuffer[][]>
-{
-
- public CqlReader(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected String buildQuery()
- {
- StringBuilder query = new StringBuilder("SELECT ");
-
- if (state.settings.columns.slice)
- {
- if (state.isCql2())
- query.append("FIRST ").append(state.settings.columns.maxColumnsPerKey).append(" ''..''");
- else
- query.append("*");
- }
- else
- {
- try
- {
- for (int i = 0; i < state.settings.columns.names.size() ; i++)
- {
- if (i > 0)
- query.append(",");
- query.append(wrapInQuotesIfRequired(ByteBufferUtil.string(state.settings.columns.names.get(i))));
- }
- }
- catch (CharacterCodingException e)
- {
- throw new IllegalStateException(e);
- }
- }
-
- query.append(" FROM ").append(wrapInQuotesIfRequired(state.type.table));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
- query.append(" WHERE KEY=?");
- return query.toString();
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- return Collections.<Object>singletonList(ByteBuffer.wrap(key));
- }
-
- @Override
- protected CqlRunOp<ByteBuffer[][]> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- List<ByteBuffer> expectRow = state.rowGen.isDeterministic() ? generateColumnValues(key) : null;
- return new CqlRunOpMatchResults(client, query, queryId, params, keyid, key, Arrays.asList(expectRow));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java b/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
new file mode 100644
index 0000000..914d212
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
@@ -0,0 +1,25 @@
+package org.apache.cassandra.stress.operations;
+
+import org.apache.cassandra.stress.Operation;
+
+public class FixedOpDistribution implements OpDistribution
+{
+
+ final Operation operation;
+
+ public FixedOpDistribution(Operation operation)
+ {
+ this.operation = operation;
+ }
+
+ public Operation next()
+ {
+ return operation;
+ }
+
+ public int maxBatchSize()
+ {
+ return (int) operation.partitionCount.maxValue();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
new file mode 100644
index 0000000..a744f18
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
@@ -0,0 +1,11 @@
+package org.apache.cassandra.stress.operations;
+
+import org.apache.cassandra.stress.Operation;
+
+public interface OpDistribution
+{
+
+ Operation next();
+ public int maxBatchSize();
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
new file mode 100644
index 0000000..08d5f56
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
@@ -0,0 +1,12 @@
+package org.apache.cassandra.stress.operations;
+
+import org.apache.cassandra.stress.util.Timer;
+
+public interface OpDistributionFactory
+{
+
+ public OpDistribution get(Timer timer);
+ public String desc();
+ Iterable<OpDistributionFactory> each();
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
new file mode 100644
index 0000000..8bd2806
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
@@ -0,0 +1,41 @@
+package org.apache.cassandra.stress.operations;
+
+import org.apache.commons.math3.distribution.EnumeratedDistribution;
+import org.apache.commons.math3.util.Pair;
+
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.generate.Distribution;
+
+public class SampledOpDistribution implements OpDistribution
+{
+
+ final EnumeratedDistribution<Operation> operations;
+ final Distribution clustering;
+ private Operation cur;
+ private long remaining;
+
+ public SampledOpDistribution(EnumeratedDistribution<Operation> operations, Distribution clustering)
+ {
+ this.operations = operations;
+ this.clustering = clustering;
+ }
+
+ public int maxBatchSize()
+ {
+ int max = 1;
+ for (Pair<Operation, Double> pair : operations.getPmf())
+ max = Math.max(max, (int) pair.getFirst().partitionCount.maxValue());
+ return max;
+ }
+
+ public Operation next()
+ {
+ while (remaining == 0)
+ {
+ remaining = clustering.next();
+ cur = operations.sample();
+ }
+ remaining--;
+ return cur;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
new file mode 100644
index 0000000..575da12
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
@@ -0,0 +1,72 @@
+package org.apache.cassandra.stress.operations;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.math3.distribution.EnumeratedDistribution;
+import org.apache.commons.math3.util.Pair;
+
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.util.Timer;
+
+public abstract class SampledOpDistributionFactory<T> implements OpDistributionFactory
+{
+
+ final List<Pair<T, Double>> ratios;
+ final DistributionFactory clustering;
+ protected SampledOpDistributionFactory(List<Pair<T, Double>> ratios, DistributionFactory clustering)
+ {
+ this.ratios = ratios;
+ this.clustering = clustering;
+ }
+
+ protected abstract Operation get(Timer timer, PartitionGenerator generator, T key);
+ protected abstract PartitionGenerator newGenerator();
+
+ public OpDistribution get(Timer timer)
+ {
+ PartitionGenerator generator = newGenerator();
+ List<Pair<Operation, Double>> operations = new ArrayList<>();
+ for (Pair<T, Double> ratio : ratios)
+ operations.add(new Pair<>(get(timer, generator, ratio.getFirst()), ratio.getSecond()));
+ return new SampledOpDistribution(new EnumeratedDistribution<>(operations), clustering.get());
+ }
+
+ public String desc()
+ {
+ List<T> keys = new ArrayList<>();
+ for (Pair<T, Double> p : ratios)
+ keys.add(p.getFirst());
+ return keys.toString();
+ }
+
+ public Iterable<OpDistributionFactory> each()
+ {
+ List<OpDistributionFactory> out = new ArrayList<>();
+ for (final Pair<T, Double> ratio : ratios)
+ {
+ out.add(new OpDistributionFactory()
+ {
+ public OpDistribution get(Timer timer)
+ {
+ return new FixedOpDistribution(SampledOpDistributionFactory.this.get(timer, newGenerator(), ratio.getFirst()));
+ }
+
+ public String desc()
+ {
+ return ratio.getFirst().toString();
+ }
+
+ public Iterable<OpDistributionFactory> each()
+ {
+ return Collections.<OpDistributionFactory>singleton(this);
+ }
+ });
+ }
+ return out;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java
deleted file mode 100644
index 9bfe440..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-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;
-import org.apache.cassandra.thrift.*;
-
-public class ThriftCounterAdder extends Operation
-{
- public ThriftCounterAdder(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
- List<CounterColumn> columns = new ArrayList<>();
- for (ByteBuffer name : randomNames())
- columns.add(new CounterColumn(name, state.counteradd.next()));
-
- Map<String, List<Mutation>> row;
- if (state.settings.columns.useSuperColumns)
- {
- List<Mutation> mutations = new ArrayList<>();
- for (ColumnParent parent : state.columnParents)
- {
- CounterSuperColumn csc = new CounterSuperColumn(ByteBuffer.wrap(parent.getSuper_column()), columns);
- ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setCounter_super_column(csc);
- mutations.add(new Mutation().setColumn_or_supercolumn(cosc));
- }
- row = Collections.singletonMap(state.type.supertable, mutations);
- }
- else
- {
- List<Mutation> mutations = new ArrayList<>(columns.size());
- for (CounterColumn c : columns)
- {
- ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setCounter_column(c);
- mutations.add(new Mutation().setColumn_or_supercolumn(cosc));
- }
- row = Collections.singletonMap(state.type.table, mutations);
- }
-
- final ByteBuffer key = getKey();
- final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
-
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- client.batch_mutate(record, state.settings.command.consistencyLevel);
- return true;
- }
-
- @Override
- public String key()
- {
- return new String(key.array());
- }
-
- @Override
- public int keyCount()
- {
- return 1;
- }
- });
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java
deleted file mode 100644
index 6e36a28..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.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;
-import org.apache.cassandra.thrift.ColumnParent;
-import org.apache.cassandra.thrift.SlicePredicate;
-import org.apache.cassandra.thrift.SliceRange;
-
-public class ThriftCounterGetter extends Operation
-{
- public ThriftCounterGetter(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
- final SlicePredicate predicate = slicePredicate();
- final ByteBuffer key = getKey();
- for (final ColumnParent parent : state.columnParents)
- {
-
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- List<?> r = client.get_slice(key, parent, predicate, state.settings.command.consistencyLevel);
- return r != null && r.size() > 0;
- }
-
- @Override
- public String key()
- {
- return new String(key.array());
- }
-
- @Override
- public int keyCount()
- {
- return 1;
- }
- });
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java
deleted file mode 100644
index 8c8ec31..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.util.ThriftClient;
-import org.apache.cassandra.thrift.*;
-import org.apache.cassandra.utils.ByteBufferUtil;
-import org.apache.cassandra.utils.FBUtilities;
-
-public class ThriftIndexedRangeSlicer extends Operation
-{
- public ThriftIndexedRangeSlicer(State state, long index)
- {
- super(state, index);
- if (!state.rowGen.isDeterministic() || !state.keyGen.isDeterministic())
- throw new IllegalStateException("Only run with a isDeterministic row/key generator");
- if (state.settings.columns.useSuperColumns || state.columnParents.size() != 1)
- throw new IllegalStateException("Does not support super columns");
- if (state.settings.columns.useTimeUUIDComparator)
- throw new IllegalStateException("Does not support TimeUUID column names");
- }
-
- public void run(final ThriftClient client) throws IOException
- {
-
- final SlicePredicate predicate = new SlicePredicate()
- .setSlice_range(new SliceRange(ByteBufferUtil.EMPTY_BYTE_BUFFER,
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- false, state.settings.columns.maxColumnsPerKey));
- final List<ByteBuffer> columns = generateColumnValues(getKey());
- final ColumnParent parent = state.columnParents.get(0);
-
- 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);
- byte[] minKey = new byte[0];
- final List<KeySlice>[] results = new List[1];
- do
- {
-
- final boolean first = minKey.length == 0;
- final IndexClause clause = new IndexClause(Arrays.asList(expression),
- ByteBuffer.wrap(minKey),
- state.settings.command.keysAtOnce);
-
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- results[0] = client.get_indexed_slices(parent, clause, predicate, state.settings.command.consistencyLevel);
- return !first || results[0].size() > 0;
- }
-
- @Override
- public String key()
- {
- return new String(value.array());
- }
-
- @Override
- public int keyCount()
- {
- return results[0].size();
- }
- });
-
- minKey = getNextMinKey(minKey, results[0]);
-
- } while (results[0].size() > 0);
- }
-
- /**
- * Get maximum key from keySlice list
- * @param slices list of the KeySlice objects
- * @return maximum key value of the list
- */
- private static byte[] getNextMinKey(byte[] cur, List<KeySlice> slices)
- {
- // find max
- for (KeySlice slice : slices)
- if (FBUtilities.compareUnsigned(cur, slice.getKey()) < 0)
- cur = slice.getKey();
-
- // increment
- for (int i = 0 ; i < cur.length ; i++)
- if (++cur[i] != 0)
- break;
- return cur;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java
deleted file mode 100644
index 7077a95..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.cassandra.db.marshal.TimeUUIDType;
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.util.ThriftClient;
-import org.apache.cassandra.thrift.*;
-import org.apache.cassandra.utils.FBUtilities;
-import org.apache.cassandra.utils.UUIDGen;
-
-public final class ThriftInserter extends Operation
-{
-
- public ThriftInserter(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
- final ByteBuffer key = getKey();
- final List<Column> columns = generateColumns(key);
-
- Map<String, List<Mutation>> row;
- if (!state.settings.columns.useSuperColumns)
- {
- List<Mutation> mutations = new ArrayList<>(columns.size());
- for (Column c : columns)
- {
- ColumnOrSuperColumn column = new ColumnOrSuperColumn().setColumn(c);
- mutations.add(new Mutation().setColumn_or_supercolumn(column));
- }
- row = Collections.singletonMap(state.type.table, mutations);
- }
- else
- {
- List<Mutation> mutations = new ArrayList<>(state.columnParents.size());
- for (ColumnParent parent : state.columnParents)
- {
- final SuperColumn s = new SuperColumn(parent.bufferForSuper_column(), columns);
- final ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setSuper_column(s);
- mutations.add(new Mutation().setColumn_or_supercolumn(cosc));
- }
- row = Collections.singletonMap(state.settings.command.type.supertable, mutations);
- }
-
- final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
-
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- client.batch_mutate(record, state.settings.command.consistencyLevel);
- return true;
- }
-
- @Override
- public String key()
- {
- return new String(key.array());
- }
-
- @Override
- public int keyCount()
- {
- return 1;
- }
- });
- }
-
- protected List<Column> generateColumns(ByteBuffer key)
- {
- final List<ByteBuffer> values = generateColumnValues(key);
- final List<Column> columns = new ArrayList<>(values.size());
-
- if (state.settings.columns.useTimeUUIDComparator)
- for (int i = 0 ; i < values.size() ; i++)
- new Column(TimeUUIDType.instance.decompose(UUIDGen.getTimeUUID()));
- else
- // 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(state.settings.columns.names.get(i)));
-
- for (int i = 0 ; i < values.size() ; i++)
- columns.get(i)
- .setValue(values.get(i))
- .setTimestamp(FBUtilities.timestampMicros());
-
- return columns;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java
deleted file mode 100644
index d8e0117..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.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;
-import org.apache.cassandra.thrift.ColumnParent;
-import org.apache.cassandra.thrift.SlicePredicate;
-import org.apache.cassandra.thrift.SliceRange;
-import org.apache.cassandra.utils.ByteBufferUtil;
-
-
-public final class ThriftMultiGetter extends Operation
-{
-
- public ThriftMultiGetter(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
-
- final SlicePredicate predicate = new SlicePredicate().setSlice_range(
- new SliceRange(
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- false,
- state.settings.columns.maxColumnsPerKey
- )
- );
-
- final List<ByteBuffer> keys = getKeys(state.settings.command.keysAtOnce);
-
- for (final ColumnParent parent : state.columnParents)
- {
- timeWithRetry(new RunOp()
- {
- int count;
- @Override
- public boolean run() throws Exception
- {
- return (count = client.multiget_slice(keys, parent, predicate, state.settings.command.consistencyLevel).size()) != 0;
- }
-
- @Override
- public String key()
- {
- return keys.toString();
- }
-
- @Override
- public int keyCount()
- {
- return count;
- }
- });
- }
- }
-
-}
[08/23] git commit: Introduce CQL support for stress tool
Posted by be...@apache.org.
Introduce CQL support for stress tool
patch by Jake Luciani and Benedict Elliott Smith
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/75364296
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/75364296
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/75364296
Branch: refs/heads/cassandra-2.1
Commit: 75364296cb3749dfa6d4307cf055f1a18bcf7a9b
Parents: 61ee287
Author: Benedict Elliott Smith <be...@apache.org>
Authored: Mon Jul 7 18:03:59 2014 +0100
Committer: Benedict Elliott Smith <be...@apache.org>
Committed: Mon Jul 7 18:25:11 2014 +0100
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../cassandra/thrift/ThriftConversion.java | 19 +
.../org/apache/cassandra/utils/UUIDGen.java | 8 +
tools/bin/cassandra-stress | 2 +-
tools/cqlstress-counter-example.yaml | 85 +++
tools/cqlstress-example.yaml | 99 +++
tools/cqlstress-insanity-example.yaml | 102 +++
.../org/apache/cassandra/stress/Operation.java | 218 +-----
.../apache/cassandra/stress/StressAction.java | 262 +++----
.../apache/cassandra/stress/StressMetrics.java | 17 +-
.../apache/cassandra/stress/StressProfile.java | 504 +++++++++++++
.../org/apache/cassandra/stress/StressYaml.java | 38 +
.../cassandra/stress/generate/Distribution.java | 57 ++
.../generate/DistributionBoundApache.java | 84 +++
.../stress/generate/DistributionFactory.java | 31 +
.../stress/generate/DistributionFixed.java | 54 ++
.../stress/generate/DistributionInverted.java | 37 +
.../generate/DistributionOffsetApache.java | 80 +++
.../cassandra/stress/generate/Partition.java | 343 +++++++++
.../stress/generate/PartitionGenerator.java | 80 +++
.../stress/generate/RatioDistribution.java | 25 +
.../generate/RatioDistributionFactory.java | 31 +
.../apache/cassandra/stress/generate/Row.java | 22 +
.../stress/generate/SeedGenerator.java | 8 +
.../stress/generate/SeedRandomGenerator.java | 33 +
.../stress/generate/SeedSeriesGenerator.java | 21 +
.../stress/generate/values/Booleans.java | 37 +
.../cassandra/stress/generate/values/Bytes.java | 54 ++
.../cassandra/stress/generate/values/Dates.java | 46 ++
.../stress/generate/values/Doubles.java | 37 +
.../stress/generate/values/Floats.java | 37 +
.../stress/generate/values/Generator.java | 50 ++
.../stress/generate/values/GeneratorConfig.java | 68 ++
.../stress/generate/values/HexBytes.java | 56 ++
.../stress/generate/values/HexStrings.java | 55 ++
.../cassandra/stress/generate/values/Inets.java | 57 ++
.../stress/generate/values/Integers.java | 38 +
.../cassandra/stress/generate/values/Lists.java | 55 ++
.../cassandra/stress/generate/values/Longs.java | 37 +
.../cassandra/stress/generate/values/Sets.java | 54 ++
.../stress/generate/values/Strings.java | 49 ++
.../stress/generate/values/TimeUUIDs.java | 51 ++
.../cassandra/stress/generate/values/UUIDs.java | 39 +
.../cassandra/stress/generatedata/DataGen.java | 39 -
.../stress/generatedata/DataGenBytesRandom.java | 45 --
.../stress/generatedata/DataGenFactory.java | 30 -
.../stress/generatedata/DataGenHex.java | 60 --
.../DataGenHexFromDistribution.java | 66 --
.../generatedata/DataGenHexFromOpIndex.java | 48 --
.../generatedata/DataGenStringDictionary.java | 107 ---
.../generatedata/DataGenStringRepeats.java | 90 ---
.../stress/generatedata/Distribution.java | 40 --
.../generatedata/DistributionBoundApache.java | 63 --
.../generatedata/DistributionFactory.java | 31 -
.../stress/generatedata/DistributionFixed.java | 46 --
.../generatedata/DistributionOffsetApache.java | 61 --
.../generatedata/DistributionSeqBatch.java | 68 --
.../cassandra/stress/generatedata/KeyGen.java | 54 --
.../cassandra/stress/generatedata/RowGen.java | 53 --
.../generatedata/RowGenDistributedSize.java | 116 ---
.../stress/operations/CqlCounterAdder.java | 77 --
.../stress/operations/CqlCounterGetter.java | 69 --
.../operations/CqlIndexedRangeSlicer.java | 118 ---
.../stress/operations/CqlInserter.java | 88 ---
.../stress/operations/CqlMultiGetter.java | 42 --
.../stress/operations/CqlOperation.java | 698 ------------------
.../stress/operations/CqlRangeSlicer.java | 59 --
.../cassandra/stress/operations/CqlReader.java | 91 ---
.../stress/operations/FixedOpDistribution.java | 25 +
.../stress/operations/OpDistribution.java | 11 +
.../operations/OpDistributionFactory.java | 12 +
.../operations/SampledOpDistribution.java | 41 ++
.../SampledOpDistributionFactory.java | 72 ++
.../stress/operations/ThriftCounterAdder.java | 95 ---
.../stress/operations/ThriftCounterGetter.java | 68 --
.../operations/ThriftIndexedRangeSlicer.java | 114 ---
.../stress/operations/ThriftInserter.java | 117 ---
.../stress/operations/ThriftMultiGetter.java | 80 ---
.../stress/operations/ThriftRangeSlicer.java | 85 ---
.../stress/operations/ThriftReader.java | 94 ---
.../operations/predefined/CqlCounterAdder.java | 84 +++
.../operations/predefined/CqlCounterGetter.java | 74 ++
.../operations/predefined/CqlInserter.java | 79 ++
.../operations/predefined/CqlOperation.java | 714 +++++++++++++++++++
.../stress/operations/predefined/CqlReader.java | 87 +++
.../predefined/PredefinedOperation.java | 248 +++++++
.../predefined/ThriftCounterAdder.java | 86 +++
.../predefined/ThriftCounterGetter.java | 66 ++
.../operations/predefined/ThriftInserter.java | 96 +++
.../operations/predefined/ThriftReader.java | 79 ++
.../operations/userdefined/SchemaInsert.java | 144 ++++
.../operations/userdefined/SchemaQuery.java | 86 +++
.../operations/userdefined/SchemaStatement.java | 164 +++++
.../cassandra/stress/settings/Command.java | 24 +-
.../stress/settings/CommandCategory.java | 4 +-
.../stress/settings/OptionAnyProbabilities.java | 78 ++
.../stress/settings/OptionDataGen.java | 203 ------
.../stress/settings/OptionDistribution.java | 75 +-
.../settings/OptionEnumProbabilities.java | 62 ++
.../cassandra/stress/settings/OptionMulti.java | 3 +-
.../settings/OptionRatioDistribution.java | 166 +++++
.../cassandra/stress/settings/OptionSimple.java | 5 +-
.../stress/settings/SettingsColumn.java | 50 +-
.../stress/settings/SettingsCommand.java | 58 +-
.../stress/settings/SettingsCommandMixed.java | 207 ------
.../settings/SettingsCommandPreDefined.java | 145 ++++
.../SettingsCommandPreDefinedMixed.java | 151 ++++
.../stress/settings/SettingsCommandUser.java | 135 ++++
.../cassandra/stress/settings/SettingsKey.java | 27 +-
.../cassandra/stress/settings/SettingsMisc.java | 2 +-
.../cassandra/stress/settings/SettingsMode.java | 6 +-
.../stress/settings/SettingsSchema.java | 77 +-
.../stress/settings/SettingsTransport.java | 2 +-
.../stress/settings/StressSettings.java | 36 +-
.../stress/settings/ValidationType.java | 8 +
.../cassandra/stress/util/JavaDriverClient.java | 19 +-
.../stress/util/SmartThriftClient.java | 4 +-
.../org/apache/cassandra/stress/util/Timer.java | 17 +-
.../cassandra/stress/util/TimingInterval.java | 26 +-
119 files changed, 5861 insertions(+), 3890 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 491ad6d..ff2f586 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
2.1.0-rc3
+ * Introduce CQL support for stress tool (CASSANDRA-6146)
* Fix ClassCastException processing expired messages (CASSANDRA-7496)
* Fix prepared marker for collections inside UDT (CASSANDRA-7472)
* Remove left-over populate_io_cache_on_flush and replicate_on_write
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/src/java/org/apache/cassandra/thrift/ThriftConversion.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/thrift/ThriftConversion.java b/src/java/org/apache/cassandra/thrift/ThriftConversion.java
index 9573b56..0c75d2c 100644
--- a/src/java/org/apache/cassandra/thrift/ThriftConversion.java
+++ b/src/java/org/apache/cassandra/thrift/ThriftConversion.java
@@ -51,6 +51,25 @@ public class ThriftConversion
throw new AssertionError();
}
+ public static ConsistencyLevel toThrift(org.apache.cassandra.db.ConsistencyLevel cl)
+ {
+ switch (cl)
+ {
+ case ANY: return ConsistencyLevel.ANY;
+ case ONE: return ConsistencyLevel.ONE;
+ case TWO: return ConsistencyLevel.TWO;
+ case THREE: return ConsistencyLevel.THREE;
+ case QUORUM: return ConsistencyLevel.QUORUM;
+ case ALL: return ConsistencyLevel.ALL;
+ case LOCAL_QUORUM: return ConsistencyLevel.LOCAL_QUORUM;
+ case EACH_QUORUM: return ConsistencyLevel.EACH_QUORUM;
+ case SERIAL: return ConsistencyLevel.SERIAL;
+ case LOCAL_SERIAL: return ConsistencyLevel.LOCAL_SERIAL;
+ case LOCAL_ONE: return ConsistencyLevel.LOCAL_ONE;
+ }
+ throw new AssertionError();
+ }
+
// We never return, but returning a RuntimeException allows to write "throw rethrow(e)" without java complaining
// for methods that have a return value.
public static RuntimeException rethrow(RequestExecutionException e) throws UnavailableException, TimedOutException
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/src/java/org/apache/cassandra/utils/UUIDGen.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/utils/UUIDGen.java b/src/java/org/apache/cassandra/utils/UUIDGen.java
index f385744..53293b2 100644
--- a/src/java/org/apache/cassandra/utils/UUIDGen.java
+++ b/src/java/org/apache/cassandra/utils/UUIDGen.java
@@ -25,6 +25,8 @@ import java.util.Collection;
import java.util.Random;
import java.util.UUID;
+import com.google.common.annotations.VisibleForTesting;
+
/**
* The goods are here: www.ietf.org/rfc/rfc4122.txt.
@@ -80,6 +82,12 @@ public class UUIDGen
return new UUID(createTime(fromUnixTimestamp(when)), clockSeqAndNode);
}
+ @VisibleForTesting
+ public static UUID getTimeUUID(long when, long clockSeqAndNode)
+ {
+ return new UUID(createTime(fromUnixTimestamp(when)), clockSeqAndNode);
+ }
+
/** creates a type 1 uuid from raw bytes. */
public static UUID getUUID(ByteBuffer raw)
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/bin/cassandra-stress
----------------------------------------------------------------------
diff --git a/tools/bin/cassandra-stress b/tools/bin/cassandra-stress
index 39257cd..c855cf5 100755
--- a/tools/bin/cassandra-stress
+++ b/tools/bin/cassandra-stress
@@ -42,4 +42,4 @@ if [ "x$JAVA" = "x" ]; then
exit 1
fi
-$JAVA -server -cp $CLASSPATH org.apache.cassandra.stress.Stress $@
+$JAVA -server -ea -cp $CLASSPATH org.apache.cassandra.stress.Stress $@
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/cqlstress-counter-example.yaml
----------------------------------------------------------------------
diff --git a/tools/cqlstress-counter-example.yaml b/tools/cqlstress-counter-example.yaml
new file mode 100644
index 0000000..a65080a
--- /dev/null
+++ b/tools/cqlstress-counter-example.yaml
@@ -0,0 +1,85 @@
+#
+# This is an example YAML profile for cassandra-stress
+#
+# insert data
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1)
+#
+# read, using query simple1:
+# cassandra-stress profile=/home/jake/stress1.yaml ops(simple1=1)
+#
+# mixed workload (90/10)
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1,simple1=9)
+
+
+#
+# Keyspace info
+#
+keyspace: stresscql
+
+#
+# The CQL for creating a keyspace (optional if it already exists)
+#
+keyspace_definition: |
+ CREATE KEYSPACE stresscql WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
+
+#
+# Table info
+#
+table: counttest
+
+#
+# The CQL for creating a table you wish to stress (optional if it already exists)
+#
+table_definition: |
+ CREATE TABLE counttest (
+ name text PRIMARY KEY,
+ count counter
+ ) WITH comment='A table of many types to test wide rows'
+
+#
+# Optional meta information on the generated columns in the above table
+# The min and max only apply to text and blob types
+# The distribution field represents the total unique population
+# distribution of that column across rows. Supported types are
+#
+# EXP(min..max) An exponential distribution over the range [min..max]
+# EXTREME(min..max,shape) An extreme value (Weibull) distribution over the range [min..max]
+# GAUSSIAN(min..max,stdvrng) A gaussian/normal distribution, where mean=(min+max)/2, and stdev is (mean-min)/stdvrng
+# GAUSSIAN(min..max,mean,stdev) A gaussian/normal distribution, with explicitly defined mean and stdev
+# UNIFORM(min..max) A uniform distribution over the range [min, max]
+# FIXED(val) A fixed distribution, always returning the same value
+# Aliases: extr, gauss, normal, norm, weibull
+#
+# If preceded by ~, the distribution is inverted
+#
+# Defaults for all columns are size: uniform(1..256), identity: uniform(1..1024)
+#
+
+columnspec:
+ - name: name
+ clustering: uniform(1..100)
+ size: uniform(1..4)
+ - name: count
+ population: fixed(1)
+
+insert:
+ partitions: fixed(1) # number of unique partitions to update in a single operation
+ # if perbatch < 1, multiple batches will be used but all partitions will
+ # occur in all batches (unless already finished); only the row counts will vary
+ pervisit: fixed(1)/1 # ratio of rows each partition should update in a single visit to the partition,
+ # as a proportion of the total possible for the partition
+ perbatch: fixed(1)/1 # number of rows each partition should update in a single batch statement,
+ # as a proportion of the proportion we are inserting this visit
+ # (i.e. compounds with (and capped by) pervisit)
+ batchtype: UNLOGGED # type of batch to use
+
+#
+# A list of queries you wish to run against the schema
+#
+queries:
+ simple1: select * from counttest where name = ?
+
+#
+# In order to generate data consistently we need something to generate a unique key for this schema profile.
+#
+seed: changing this string changes the generated data. its hashcode is used as the random seed.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/cqlstress-example.yaml
----------------------------------------------------------------------
diff --git a/tools/cqlstress-example.yaml b/tools/cqlstress-example.yaml
new file mode 100644
index 0000000..a997529
--- /dev/null
+++ b/tools/cqlstress-example.yaml
@@ -0,0 +1,99 @@
+#
+# This is an example YAML profile for cassandra-stress
+#
+# insert data
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1)
+#
+# read, using query simple1:
+# cassandra-stress profile=/home/jake/stress1.yaml ops(simple1=1)
+#
+# mixed workload (90/10)
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1,simple1=9)
+
+
+#
+# Keyspace info
+#
+keyspace: stresscql
+
+#
+# The CQL for creating a keyspace (optional if it already exists)
+#
+keyspace_definition: |
+ CREATE KEYSPACE stresscql WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
+
+#
+# Table info
+#
+table: typestest
+
+#
+# The CQL for creating a table you wish to stress (optional if it already exists)
+#
+table_definition: |
+ CREATE TABLE typestest (
+ name text,
+ choice boolean,
+ date timestamp,
+ address inet,
+ dbl double,
+ lval bigint,
+ ival int,
+ uid timeuuid,
+ value blob,
+ PRIMARY KEY((name,choice), date, address, dbl, lval, ival, uid)
+ ) WITH COMPACT STORAGE
+ AND compaction = { 'class':'LeveledCompactionStrategy' }
+ AND comment='A table of many types to test wide rows'
+
+#
+# Optional meta information on the generated columns in the above table
+# The min and max only apply to text and blob types
+# The distribution field represents the total unique population
+# distribution of that column across rows. Supported types are
+#
+# EXP(min..max) An exponential distribution over the range [min..max]
+# EXTREME(min..max,shape) An extreme value (Weibull) distribution over the range [min..max]
+# GAUSSIAN(min..max,stdvrng) A gaussian/normal distribution, where mean=(min+max)/2, and stdev is (mean-min)/stdvrng
+# GAUSSIAN(min..max,mean,stdev) A gaussian/normal distribution, with explicitly defined mean and stdev
+# UNIFORM(min..max) A uniform distribution over the range [min, max]
+# FIXED(val) A fixed distribution, always returning the same value
+# Aliases: extr, gauss, normal, norm, weibull
+#
+# If preceded by ~, the distribution is inverted
+#
+# Defaults for all columns are size: uniform(1..256), identity: uniform(1..1024)
+#
+columnspec:
+ - name: name
+ size: uniform(1..10)
+ population: uniform(1..1M) # the range of unique values to select for the field (default is 100Billion)
+ - name: choice
+ - name: date
+ cluster: uniform(1..4)
+ - name: lval
+ population: gaussian(1..1000)
+ cluster: uniform(1..4)
+
+insert:
+ partitions: uniform(1..50) # number of unique partitions to update in a single operation
+ # if perbatch < 1, multiple batches will be used but all partitions will
+ # occur in all batches (unless already finished); only the row counts will vary
+ pervisit: uniform(1..10)/10 # ratio of rows each partition should update in a single visit to the partition,
+ # as a proportion of the total possible for the partition
+ perbatch: ~exp(1..3)/4 # number of rows each partition should update in a single batch statement,
+ # as a proportion of the proportion we are inserting this visit
+ # (i.e. compounds with (and capped by) pervisit)
+ batchtype: UNLOGGED # type of batch to use
+
+#
+# A list of queries you wish to run against the schema
+#
+queries:
+ simple1: select * from typestest where name = ? and choice = ? LIMIT 100
+ range1: select * from typestest where name = ? and choice = ? and date >= ? LIMIT 100
+
+#
+# In order to generate data consistently we need something to generate a unique key for this schema profile.
+#
+seed: changing this string changes the generated data. its hashcode is used as the random seed.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/cqlstress-insanity-example.yaml
----------------------------------------------------------------------
diff --git a/tools/cqlstress-insanity-example.yaml b/tools/cqlstress-insanity-example.yaml
new file mode 100644
index 0000000..e94c9c3
--- /dev/null
+++ b/tools/cqlstress-insanity-example.yaml
@@ -0,0 +1,102 @@
+#
+# This is an example YAML profile for cassandra-stress
+#
+# insert data
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1)
+#
+# read, using query simple1:
+# cassandra-stress profile=/home/jake/stress1.yaml ops(simple1=1)
+#
+# mixed workload (90/10)
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1,simple1=9)
+
+
+#
+# Keyspace info
+#
+keyspace: stresscql
+
+#
+# The CQL for creating a keyspace (optional if it already exists)
+#
+keyspace_definition: |
+ CREATE KEYSPACE stresscql WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
+
+#
+# Table info
+#
+table: insanitytest
+
+#
+# The CQL for creating a table you wish to stress (optional if it already exists)
+#
+table_definition: |
+ CREATE TABLE insanitytest (
+ name text,
+ choice boolean,
+ date timestamp,
+ address inet,
+ dbl double,
+ lval bigint,
+ fval float,
+ ival int,
+ uid timeuuid,
+ dates list<timestamp>,
+ inets set<inet>,
+ value blob,
+ PRIMARY KEY((name, choice), date)
+ ) WITH compaction = { 'class':'LeveledCompactionStrategy' }
+ AND comment='A table of many types to test wide rows and collections'
+
+#
+# Optional meta information on the generated columns in the above table
+# The min and max only apply to text and blob types
+# The distribution field represents the total unique population
+# distribution of that column across rows. Supported types are
+#
+# EXP(min..max) An exponential distribution over the range [min..max]
+# EXTREME(min..max,shape) An extreme value (Weibull) distribution over the range [min..max]
+# GAUSSIAN(min..max,stdvrng) A gaussian/normal distribution, where mean=(min+max)/2, and stdev is (mean-min)/stdvrng
+# GAUSSIAN(min..max,mean,stdev) A gaussian/normal distribution, with explicitly defined mean and stdev
+# UNIFORM(min..max) A uniform distribution over the range [min, max]
+# FIXED(val) A fixed distribution, always returning the same value
+# Aliases: extr, gauss, normal, norm, weibull
+#
+# If preceded by ~, the distribution is inverted
+#
+# Defaults for all columns are size: uniform(1..256), population: uniform(1..100B)
+#
+columnspec:
+ - name: name
+ clustering: uniform(1..4)
+ - name: date
+ clustering: gaussian(1..20)
+ - name: lval
+ population: fixed(1)
+ - name: dates
+ clustering: uniform(1..100)
+ - name: inets
+ clustering: uniform(1..200)
+ - name: value
+
+insert:
+ partitions: fixed(1) # number of unique partitions to update in a single operation
+ # if perbatch < 1, multiple batches will be used but all partitions will
+ # occur in all batches (unless already finished); only the row counts will vary
+ pervisit: uniform(1..10)/100K # ratio of rows each partition should update in a single visit to the partition,
+ # as a proportion of the total possible for the partition
+ perbatch: fixed(1)/1 # number of rows each partition should update in a single batch statement,
+ # as a proportion of the proportion we are inserting this visit
+ # (i.e. compounds with (and capped by) pervisit)
+ batchtype: UNLOGGED # type of batch to use
+
+#
+# A list of queries you wish to run against the schema
+#
+queries:
+ simple1: select * from insanitytest where name = ? and choice = ? LIMIT 100
+
+#
+# In order to generate data consistently we need something to generate a unique key for this schema profile.
+#
+seed: changing this string changes the generated data. its hashcode is used as the random seed.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/Operation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/Operation.java b/tools/stress/src/org/apache/cassandra/stress/Operation.java
index 87afb3d..7831074 100644
--- a/tools/stress/src/org/apache/cassandra/stress/Operation.java
+++ b/tools/stress/src/org/apache/cassandra/stress/Operation.java
@@ -18,203 +18,47 @@
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.generate.Distribution;
+import org.apache.cassandra.stress.generate.Partition;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
import org.apache.cassandra.stress.settings.*;
import org.apache.cassandra.stress.util.JavaDriverClient;
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;
public abstract class Operation
{
- public final long index;
- protected final State state;
+ public final StressSettings settings;
+ public final Timer timer;
+ public final PartitionGenerator generator;
+ public final Distribution partitionCount;
- public Operation(State state, long idx)
+ protected List<Partition> partitions;
+
+ public Operation(Timer timer, PartitionGenerator generator, StressSettings settings, Distribution partitionCount)
{
- index = idx;
- this.state = state;
+ this.generator = generator;
+ this.timer = timer;
+ this.settings = settings;
+ this.partitionCount = partitionCount;
}
public static interface RunOp
{
public boolean run() throws Exception;
- public String key();
- public int keyCount();
+ public int partitionCount();
+ public int rowCount();
}
- // one per thread!
- public static final class State
+ protected void setPartitions(List<Partition> partitions)
{
-
- public final StressSettings settings;
- public final Timer timer;
- public final Command type;
- public final KeyGen keyGen;
- public final RowGen rowGen;
- public final Distribution counteradd;
- public final List<ColumnParent> columnParents;
- public final StressMetrics metrics;
- public final SettingsCommandMixed.CommandSelector commandSelector;
- private final EnumMap<Command, State> substates;
- private Object cqlCache;
-
- public State(Command type, StressSettings settings, StressMetrics metrics)
- {
- this.type = type;
- this.timer = metrics.getTiming().newTimer();
- if (type == Command.MIXED)
- {
- commandSelector = ((SettingsCommandMixed) settings.command).selector();
- substates = new EnumMap<>(Command.class);
- }
- else
- {
- 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;
- this.columnParents = columnParents(type, settings);
- }
-
- private State(Command type, State copy)
- {
- this.type = type;
- this.timer = copy.timer;
- this.rowGen = copy.rowGen;
- this.keyGen = copy.keyGen;
- 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<ColumnParent> 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;
- }
- public boolean isCql2()
- {
- return settings.mode.cqlVersion == CqlVersion.CQL2;
- }
- public Object getCqlCache()
- {
- return cqlCache;
- }
- public void storeCqlCache(Object val)
- {
- cqlCache = val;
- }
-
- public State substate(Command command)
- {
- assert type == Command.MIXED;
- State substate = substates.get(command);
- if (substate == null)
- {
- substates.put(command, substate = new State(command, this));
- }
- return substate;
- }
-
- }
-
- protected ByteBuffer getKey()
- {
- return state.keyGen.getKeys(1, index).get(0);
- }
-
- protected List<ByteBuffer> getKeys(int count)
- {
- return state.keyGen.getKeys(count, index);
- }
-
- protected List<ByteBuffer> generateColumnValues(ByteBuffer key)
- {
- 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<ByteBuffer> randomNames()
- {
- int count = state.rowGen.count(index);
- List<ByteBuffer> src = state.settings.columns.names;
- if (count == src.size())
- return src;
- ThreadLocalRandom rnd = ThreadLocalRandom.current();
- List<ByteBuffer> 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;
+ this.partitions = partitions;
}
/**
@@ -234,13 +78,13 @@ public abstract class Operation
public void timeWithRetry(RunOp run) throws IOException
{
- state.timer.start();
+ timer.start();
boolean success = false;
String exceptionMessage = null;
int tries = 0;
- for (; tries < state.settings.command.tries; tries++)
+ for (; tries < settings.command.tries; tries++)
{
try
{
@@ -249,7 +93,7 @@ public abstract class Operation
}
catch (Exception e)
{
- switch (state.settings.log.level)
+ switch (settings.log.level)
{
case MINIMAL:
break;
@@ -269,15 +113,13 @@ public abstract class Operation
}
}
- state.timer.stop(run.keyCount());
+ timer.stop(run.partitionCount(), run.rowCount());
if (!success)
{
- error(String.format("Operation [%d] x%d key %s (0x%s) %s%n",
- index,
+ error(String.format("Operation x%d on key(s) %s: %s%n",
tries,
- run.key(),
- ByteBufferUtil.bytesToHex(ByteBufferUtil.bytes(run.key())),
+ key(),
(exceptionMessage == null)
? "Data returned was not validated"
: "Error executing: " + exceptionMessage));
@@ -285,6 +127,14 @@ public abstract class Operation
}
+ private String key()
+ {
+ List<String> keys = new ArrayList<>();
+ for (Partition partition : partitions)
+ keys.add(partition.getKeyAsString());
+ return keys.toString();
+ }
+
protected String getExceptionMessage(Exception e)
{
String className = e.getClass().getSimpleName();
@@ -294,9 +144,9 @@ public abstract class Operation
protected void error(String message) throws IOException
{
- if (!state.settings.command.ignoreErrors)
+ if (!settings.command.ignoreErrors)
throw new IOException(message);
- else if (state.settings.log.level.compareTo(SettingsLog.Level.MINIMAL) > 0)
+ else if (settings.log.level.compareTo(SettingsLog.Level.MINIMAL) > 0)
System.err.println(message);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/StressAction.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressAction.java b/tools/stress/src/org/apache/cassandra/stress/StressAction.java
index 07ba1d8..2105a72 100644
--- a/tools/stress/src/org/apache/cassandra/stress/StressAction.java
+++ b/tools/stress/src/org/apache/cassandra/stress/StressAction.java
@@ -21,6 +21,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
@@ -29,10 +30,15 @@ import java.util.concurrent.atomic.AtomicLong;
import com.google.common.util.concurrent.RateLimiter;
import com.google.common.util.concurrent.Uninterruptibles;
-import org.apache.cassandra.stress.operations.*;
+
+import org.apache.cassandra.stress.generate.Partition;
+import org.apache.cassandra.stress.generate.SeedGenerator;
+import org.apache.cassandra.stress.operations.OpDistribution;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
import org.apache.cassandra.stress.settings.*;
import org.apache.cassandra.stress.util.JavaDriverClient;
import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
import org.apache.cassandra.transport.SimpleClient;
public class StressAction implements Runnable
@@ -52,7 +58,8 @@ public class StressAction implements Runnable
// creating keyspace and column families
settings.maybeCreateKeyspaces();
- warmup(settings.command.type, settings.command);
+ if (!settings.command.noWarmup)
+ warmup(settings.command.getFactory(settings));
output.println("Sleeping 2s...");
Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
@@ -61,7 +68,7 @@ public class StressAction implements Runnable
if (settings.rate.auto)
success = runAuto();
else
- success = null != run(settings.command.type, settings.rate.threadCount, settings.command.count, output);
+ success = null != run(settings.command.getFactory(settings), settings.rate.threadCount, settings.command.count, output);
if (success)
output.println("END");
@@ -72,33 +79,18 @@ public class StressAction implements Runnable
}
// type provided separately to support recursive call for mixed command with each command type it is performing
- private void warmup(Command type, SettingsCommand command)
+ private void warmup(OpDistributionFactory operations)
{
// warmup - do 50k iterations; by default hotspot compiles methods after 10k invocations
PrintStream warmupOutput = new PrintStream(new OutputStream() { @Override public void write(int b) throws IOException { } } );
- int iterations;
- switch (type.category)
+ int iterations = 50000 * settings.node.nodes.size();
+ for (OpDistributionFactory single : operations.each())
{
- case BASIC:
- iterations = 50000;
- break;
- case MIXED:
- for (Command subtype : ((SettingsCommandMixed) command).getCommands())
- warmup(subtype, command);
- return;
- case MULTI:
- int keysAtOnce = command.keysAtOnce;
- iterations = Math.min(50000, (int) Math.ceil(500000d / keysAtOnce));
- break;
- default:
- throw new IllegalStateException();
+ // we need to warm up all the nodes in the cluster ideally, but we may not be the only stress instance;
+ // so warm up all the nodes we're speaking to only.
+ output.println(String.format("Warming up %s with %d iterations...", single.desc(), iterations));
+ run(single, 20, iterations, warmupOutput);
}
-
- // we need to warm up all the nodes in the cluster ideally, but we may not be the only stress instance;
- // so warm up all the nodes we're speaking to only.
- iterations *= settings.node.nodes.size();
- output.println(String.format("Warming up %s with %d iterations...", type, iterations));
- run(type, 20, iterations, warmupOutput);
}
// TODO : permit varying more than just thread count
@@ -113,7 +105,7 @@ public class StressAction implements Runnable
{
output.println(String.format("Running with %d threadCount", threadCount));
- StressMetrics result = run(settings.command.type, threadCount, settings.command.count, output);
+ StressMetrics result = run(settings.command.getFactory(settings), threadCount, settings.command.count, output);
if (result == null)
return false;
results.add(result);
@@ -170,13 +162,13 @@ public class StressAction implements Runnable
return improvement / count;
}
- private StressMetrics run(Command type, int threadCount, long opCount, PrintStream output)
+ private StressMetrics run(OpDistributionFactory operations, int threadCount, long opCount, PrintStream output)
{
output.println(String.format("Running %s with %d threads %s",
- type.toString(),
- threadCount,
- opCount > 0 ? " for " + opCount + " iterations" : "until stderr of mean < " + settings.command.targetUncertainty));
+ operations.desc(),
+ threadCount,
+ opCount > 0 ? " for " + opCount + " iterations" : "until stderr of mean < " + settings.command.targetUncertainty));
final WorkQueue workQueue;
if (opCount < 0)
workQueue = new ContinuousWorkQueue(50);
@@ -193,7 +185,7 @@ public class StressAction implements Runnable
final CountDownLatch done = new CountDownLatch(threadCount);
final Consumer[] consumers = new Consumer[threadCount];
for (int i = 0; i < threadCount; i++)
- consumers[i] = new Consumer(type, done, workQueue, metrics, rateLimiter);
+ consumers[i] = new Consumer(operations, done, workQueue, metrics, rateLimiter);
// starting worker threadCount
for (int i = 0; i < threadCount; i++)
@@ -236,18 +228,24 @@ public class StressAction implements Runnable
private class Consumer extends Thread
{
- private final Operation.State state;
+ private final OpDistribution operations;
+ private final StressMetrics metrics;
+ private final Timer timer;
+ private final SeedGenerator seedGenerator;
private final RateLimiter rateLimiter;
private volatile boolean success = true;
private final WorkQueue workQueue;
private final CountDownLatch done;
- public Consumer(Command type, CountDownLatch done, WorkQueue workQueue, StressMetrics metrics, RateLimiter rateLimiter)
+ public Consumer(OpDistributionFactory operations, CountDownLatch done, WorkQueue workQueue, StressMetrics metrics, RateLimiter rateLimiter)
{
this.done = done;
this.rateLimiter = rateLimiter;
this.workQueue = workQueue;
- this.state = new Operation.State(type, settings, metrics);
+ this.metrics = metrics;
+ this.timer = metrics.getTiming().newTimer();
+ this.seedGenerator = settings.keys.newSeedGenerator();
+ this.operations = operations.get(timer);
}
public void run()
@@ -269,63 +267,89 @@ public class StressAction implements Runnable
sclient = settings.getSimpleNativeClient();
break;
case THRIFT:
- tclient = settings.getThriftClient();
- break;
case THRIFT_SMART:
- tclient = settings.getSmartThriftClient();
+ tclient = settings.getThriftClient();
break;
default:
throw new IllegalStateException();
}
- Work work;
- while ( null != (work = workQueue.poll()) )
+ int maxBatchSize = operations.maxBatchSize();
+ Work work = workQueue.poll();
+ Partition[] partitions = new Partition[maxBatchSize];
+ int workDone = 0;
+ while (work != null)
{
- if (rateLimiter != null)
- rateLimiter.acquire(work.count);
+ Operation op = operations.next();
+ op.generator.reset();
+ int batchSize = Math.max(1, (int) op.partitionCount.next());
+ int partitionCount = 0;
- for (int i = 0 ; i < work.count ; i++)
+ while (partitionCount < batchSize)
{
- try
+ int count = Math.min((work.count - workDone), batchSize - partitionCount);
+ for (int i = 0 ; i < count ; i++)
{
- Operation op = createOperation(state, i + work.offset);
- switch (settings.mode.api)
- {
- case JAVA_DRIVER_NATIVE:
- op.run(jclient);
- break;
- case SIMPLE_NATIVE:
- op.run(sclient);
- break;
- case THRIFT:
- case THRIFT_SMART:
- default:
- op.run(tclient);
- }
- } catch (Exception e)
+ long seed = seedGenerator.next(work.offset + workDone + i);
+ partitions[partitionCount + i] = op.generator.generate(seed);
+ }
+ workDone += count;
+ partitionCount += count;
+ if (workDone == work.count)
{
- if (output == null)
+ workDone = 0;
+ work = workQueue.poll();
+ if (work == null)
{
- System.err.println(e.getMessage());
- success = false;
- System.exit(-1);
+ if (partitionCount == 0)
+ return;
+ break;
}
+ if (rateLimiter != null)
+ rateLimiter.acquire(work.count);
+ }
+ }
+
+ op.setPartitions(Arrays.asList(partitions).subList(0, partitionCount));
- e.printStackTrace(output);
+ try
+ {
+ switch (settings.mode.api)
+ {
+ case JAVA_DRIVER_NATIVE:
+ op.run(jclient);
+ break;
+ case SIMPLE_NATIVE:
+ op.run(sclient);
+ break;
+ case THRIFT:
+ case THRIFT_SMART:
+ default:
+ op.run(tclient);
+ }
+ }
+ catch (Exception e)
+ {
+ if (output == null)
+ {
+ System.err.println(e.getMessage());
success = false;
- workQueue.stop();
- state.metrics.cancel();
- return;
+ System.exit(-1);
}
+
+ e.printStackTrace(output);
+ success = false;
+ workQueue.stop();
+ metrics.cancel();
+ return;
}
}
-
}
finally
{
done.countDown();
- state.timer.close();
+ timer.close();
}
}
@@ -443,106 +467,4 @@ public class StressAction implements Runnable
}
- private Operation createOperation(Operation.State state, long index)
- {
- return createOperation(state.type, state, index);
- }
- private Operation createOperation(Command type, Operation.State state, long index)
- {
- switch (type)
- {
- case READ:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftReader(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlReader(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
-
- case COUNTER_READ:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftCounterGetter(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlCounterGetter(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case WRITE:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftInserter(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlInserter(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case COUNTER_WRITE:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftCounterAdder(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlCounterAdder(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case RANGE_SLICE:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftRangeSlicer(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlRangeSlicer(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case INDEXED_RANGE_SLICE:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftIndexedRangeSlicer(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlIndexedRangeSlicer(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case READ_MULTI:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftMultiGetter(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlMultiGetter(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case MIXED:
- Command subcommand = state.commandSelector.next();
- return createOperation(subcommand, state.substate(subcommand), index);
-
- }
-
- throw new UnsupportedOperationException();
- }
-
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java b/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
index 54a1e2c..7e5c1b6 100644
--- a/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
+++ b/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
@@ -127,20 +127,21 @@ public class StressMetrics
// PRINT FORMATTING
- public static final String HEADFORMAT = "%-10s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%7s,%9s";
- public static final String ROWFORMAT = "%-10d,%8.0f,%8.0f,%8.1f,%8.1f,%8.1f,%8.1f,%8.1f,%8.1f,%7.1f,%9.5f";
+ public static final String HEADFORMAT = "%-10s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%7s,%9s";
+ public static final String ROWFORMAT = "%-10d,%8.0f,%8.0f,%8.0f,%8.1f,%8.1f,%8.1f,%8.1f,%8.1f,%8.1f,%7.1f,%9.5f";
private static void printHeader(String prefix, PrintStream output)
{
- output.println(prefix + String.format(HEADFORMAT, "ops","op/s", "key/s","mean","med",".95",".99",".999","max","time","stderr"));
+ output.println(prefix + String.format(HEADFORMAT, "partitions","op/s", "pk/s", "row/s","mean","med",".95",".99",".999","max","time","stderr"));
}
private static void printRow(String prefix, TimingInterval interval, TimingInterval total, Uncertainty opRateUncertainty, PrintStream output)
{
output.println(prefix + String.format(ROWFORMAT,
- total.operationCount,
+ total.partitionCount,
interval.realOpRate(),
- interval.keyRate(),
+ interval.partitionRate(),
+ interval.rowRate(),
interval.meanLatency(),
interval.medianLatency(),
interval.rankLatency(0.95f),
@@ -156,9 +157,9 @@ public class StressMetrics
output.println("\n");
output.println("Results:");
TimingInterval history = timing.getHistory();
- output.println(String.format("real op rate : %.0f", history.realOpRate()));
- output.println(String.format("adjusted op rate stderr : %.0f", opRateUncertainty.getUncertainty()));
- output.println(String.format("key rate : %.0f", history.keyRate()));
+ output.println(String.format("op rate : %.0f", history.realOpRate()));
+ output.println(String.format("partition rate : %.0f", history.partitionRate()));
+ output.println(String.format("row rate : %.0f", history.rowRate()));
output.println(String.format("latency mean : %.1f", history.meanLatency()));
output.println(String.format("latency median : %.1f", history.medianLatency()));
output.println(String.format("latency 95th percentile : %.1f", history.rankLatency(.95f)));
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressProfile.java b/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
new file mode 100644
index 0000000..13f26a2
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
@@ -0,0 +1,504 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress;
+
+
+import com.datastax.driver.core.*;
+import com.datastax.driver.core.exceptions.AlreadyExistsException;
+
+import com.google.common.util.concurrent.Uninterruptibles;
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.cql3.QueryProcessor;
+import org.apache.cassandra.cql3.statements.CreateKeyspaceStatement;
+import org.apache.cassandra.exceptions.RequestValidationException;
+
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.RatioDistributionFactory;
+import org.apache.cassandra.stress.generate.values.Booleans;
+import org.apache.cassandra.stress.generate.values.Bytes;
+import org.apache.cassandra.stress.generate.values.Generator;
+import org.apache.cassandra.stress.generate.values.Dates;
+import org.apache.cassandra.stress.generate.values.Doubles;
+import org.apache.cassandra.stress.generate.values.Floats;
+import org.apache.cassandra.stress.generate.values.GeneratorConfig;
+import org.apache.cassandra.stress.generate.values.Inets;
+import org.apache.cassandra.stress.generate.values.Integers;
+import org.apache.cassandra.stress.generate.values.Lists;
+import org.apache.cassandra.stress.generate.values.Longs;
+import org.apache.cassandra.stress.generate.values.Sets;
+import org.apache.cassandra.stress.generate.values.Strings;
+import org.apache.cassandra.stress.generate.values.TimeUUIDs;
+import org.apache.cassandra.stress.generate.values.UUIDs;
+import org.apache.cassandra.stress.operations.userdefined.SchemaInsert;
+import org.apache.cassandra.stress.operations.userdefined.SchemaQuery;
+import org.apache.cassandra.stress.settings.OptionDistribution;
+import org.apache.cassandra.stress.settings.OptionRatioDistribution;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.settings.ValidationType;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.Compression;
+import org.apache.cassandra.thrift.ThriftConversion;
+import org.apache.thrift.TException;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.error.YAMLException;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.Serializable;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+public class StressProfile implements Serializable
+{
+ private String keyspaceCql;
+ private String tableCql;
+ private String seedStr;
+
+ public String keyspaceName;
+ public String tableName;
+ private Map<String, GeneratorConfig> columnConfigs;
+ private Map<String, String> queries;
+ private Map<String, String> insert;
+
+ transient volatile TableMetadata tableMetaData;
+
+ transient volatile GeneratorFactory generatorFactory;
+
+ transient volatile BatchStatement.Type batchType;
+ transient volatile DistributionFactory partitions;
+ transient volatile RatioDistributionFactory pervisit;
+ transient volatile RatioDistributionFactory perbatch;
+ transient volatile PreparedStatement insertStatement;
+ transient volatile Integer thriftInsertId;
+
+ transient volatile Map<String, PreparedStatement> queryStatements;
+ transient volatile Map<String, Integer> thriftQueryIds;
+
+ private void init(StressYaml yaml) throws RequestValidationException
+ {
+ keyspaceName = yaml.keyspace;
+ keyspaceCql = yaml.keyspace_definition;
+ tableName = yaml.table;
+ tableCql = yaml.table_definition;
+ seedStr = yaml.seed;
+ queries = yaml.queries;
+ insert = yaml.insert;
+
+ assert keyspaceName != null : "keyspace name is required in yaml file";
+ assert tableName != null : "table name is required in yaml file";
+ assert queries != null : "queries map is required in yaml file";
+
+ if (keyspaceCql != null && keyspaceCql.length() > 0)
+ {
+ String name = ((CreateKeyspaceStatement) QueryProcessor.parseStatement(keyspaceCql)).keyspace();
+ assert name.equalsIgnoreCase(keyspaceName) : "Name in keyspace_definition doesn't match keyspace property: '" + name + "' != '" + keyspaceName + "'";
+ }
+ else
+ {
+ keyspaceCql = null;
+ }
+
+ if (tableCql != null && tableCql.length() > 0)
+ {
+ String name = CFMetaData.compile(tableCql, keyspaceName).cfName;
+ assert name.equalsIgnoreCase(tableName) : "Name in table_definition doesn't match table property: '" + name + "' != '" + tableName + "'";
+ }
+ else
+ {
+ tableCql = null;
+ }
+
+ columnConfigs = new HashMap<>();
+ for (Map<String,Object> spec : yaml.columnspec)
+ {
+ lowerCase(spec);
+ String name = (String) spec.remove("name");
+ DistributionFactory population = !spec.containsKey("population") ? null : OptionDistribution.get((String) spec.remove("population"));
+ DistributionFactory size = !spec.containsKey("size") ? null : OptionDistribution.get((String) spec.remove("size"));
+ DistributionFactory clustering = !spec.containsKey("cluster") ? null : OptionDistribution.get((String) spec.remove("cluster"));
+
+ if (!spec.isEmpty())
+ throw new IllegalArgumentException("Unrecognised option(s) in column spec: " + spec);
+ if (name == null)
+ throw new IllegalArgumentException("Missing name argument in column spec");
+
+ GeneratorConfig config = new GeneratorConfig(yaml.seed + name, clustering, size, population);
+ columnConfigs.put(name, config);
+ }
+ }
+
+ public void maybeCreateSchema(StressSettings settings)
+ {
+ JavaDriverClient client = settings.getJavaDriverClient(false);
+
+ if (keyspaceCql != null)
+ {
+ try
+ {
+ client.execute(keyspaceCql, org.apache.cassandra.db.ConsistencyLevel.ONE);
+ }
+ catch (AlreadyExistsException e)
+ {
+ }
+ }
+
+ client.execute("use "+keyspaceName, org.apache.cassandra.db.ConsistencyLevel.ONE);
+
+ if (tableCql != null)
+ {
+ try
+ {
+ client.execute(tableCql, org.apache.cassandra.db.ConsistencyLevel.ONE);
+ }
+ catch (AlreadyExistsException e)
+ {
+ }
+
+ System.out.println(String.format("Created schema. Sleeping %ss for propagation.", settings.node.nodes.size()));
+ Uninterruptibles.sleepUninterruptibly(settings.node.nodes.size(), TimeUnit.SECONDS);
+ }
+
+ maybeLoadSchemaInfo(settings);
+ }
+
+
+ private void maybeLoadSchemaInfo(StressSettings settings)
+ {
+ if (tableMetaData == null)
+ {
+ JavaDriverClient client = settings.getJavaDriverClient();
+
+ synchronized (client)
+ {
+
+ if (tableMetaData != null)
+ return;
+
+ TableMetadata metadata = client.getCluster()
+ .getMetadata()
+ .getKeyspace(keyspaceName)
+ .getTable(tableName);
+
+ //Fill in missing column configs
+ for (ColumnMetadata col : metadata.getColumns())
+ {
+ if (columnConfigs.containsKey(col.getName()))
+ continue;
+
+ columnConfigs.put(col.getName(), new GeneratorConfig(seedStr + col.getName(), null, null, null));
+ }
+
+ tableMetaData = metadata;
+ }
+ }
+ }
+
+ public SchemaQuery getQuery(String name, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ if (queryStatements == null)
+ {
+ synchronized (this)
+ {
+ if (queryStatements == null)
+ {
+ try
+ {
+ JavaDriverClient jclient = settings.getJavaDriverClient();
+ ThriftClient tclient = settings.getThriftClient();
+ Map<String, PreparedStatement> stmts = new HashMap<>();
+ Map<String, Integer> tids = new HashMap<>();
+ for (Map.Entry<String, String> e : queries.entrySet())
+ {
+ stmts.put(e.getKey().toLowerCase(), jclient.prepare(e.getValue()));
+ tids.put(e.getKey().toLowerCase(), tclient.prepare_cql3_query(e.getValue(), Compression.NONE));
+ }
+ thriftQueryIds = tids;
+ queryStatements = stmts;
+ }
+ catch (TException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+ // TODO validation
+ name = name.toLowerCase();
+ return new SchemaQuery(timer, generator, settings, thriftQueryIds.get(name), queryStatements.get(name), ThriftConversion.fromThrift(settings.command.consistencyLevel), ValidationType.NOT_FAIL);
+ }
+
+ public SchemaInsert getInsert(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ if (insertStatement == null)
+ {
+ synchronized (this)
+ {
+ if (insertStatement == null)
+ {
+ maybeLoadSchemaInfo(settings);
+
+ Set<ColumnMetadata> keyColumns = com.google.common.collect.Sets.newHashSet(tableMetaData.getPrimaryKey());
+
+ //Non PK Columns
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("UPDATE \"").append(tableName).append("\" SET ");
+
+ //PK Columns
+ StringBuilder pred = new StringBuilder();
+ pred.append(" WHERE ");
+
+ boolean firstCol = true;
+ boolean firstPred = true;
+ for (ColumnMetadata c : tableMetaData.getColumns())
+ {
+
+ if (keyColumns.contains(c))
+ {
+ if (firstPred)
+ firstPred = false;
+ else
+ pred.append(" AND ");
+
+ pred.append(c.getName()).append(" = ?");
+ }
+ else
+ {
+ if (firstCol)
+ firstCol = false;
+ else
+ sb.append(",");
+
+ sb.append(c.getName()).append(" = ");
+
+ switch (c.getType().getName())
+ {
+ case SET:
+ case LIST:
+ case COUNTER:
+ sb.append(c.getName()).append(" + ?");
+ break;
+ default:
+ sb.append("?");
+ break;
+ }
+ }
+ }
+
+ //Put PK predicates at the end
+ sb.append(pred);
+
+ if (insert == null)
+ insert = new HashMap<>();
+ lowerCase(insert);
+
+ partitions = OptionDistribution.get(!insert.containsKey("partitions") ? "fixed(1)" : insert.remove("partitions"));
+ pervisit = OptionRatioDistribution.get(!insert.containsKey("pervisit") ? "fixed(1)/1" : insert.remove("pervisit"));
+ perbatch = OptionRatioDistribution.get(!insert.containsKey("perbatch") ? "fixed(1)/1" : insert.remove("perbatch"));
+ batchType = !insert.containsKey("batchtype") ? BatchStatement.Type.UNLOGGED : BatchStatement.Type.valueOf(insert.remove("batchtype"));
+ if (!insert.isEmpty())
+ throw new IllegalArgumentException("Unrecognised insert option(s): " + insert);
+
+ if (generator.maxRowCount > 100 * 1000 * 1000)
+ System.err.printf("WARNING: You have defined a schema that permits very large partitions (%.0f max rows (>100M))\n", generator.maxRowCount);
+ if (perbatch.get().max() * pervisit.get().max() * partitions.get().maxValue() * generator.maxRowCount > 100000)
+ System.err.printf("WARNING: You have defined a schema that permits very large batches (%.0f max rows (>100K)). This may OOM this stress client, or the server.\n",
+ perbatch.get().max() * pervisit.get().max() * partitions.get().maxValue() * generator.maxRowCount);
+
+ JavaDriverClient client = settings.getJavaDriverClient();
+ String query = sb.toString();
+ try
+ {
+ thriftInsertId = settings.getThriftClient().prepare_cql3_query(query, Compression.NONE);
+ }
+ catch (TException e)
+ {
+ throw new RuntimeException(e);
+ }
+ insertStatement = client.prepare(query);
+ }
+ }
+ }
+
+ return new SchemaInsert(timer, generator, settings, partitions.get(), pervisit.get(), perbatch.get(), thriftInsertId, insertStatement, ThriftConversion.fromThrift(settings.command.consistencyLevel), batchType);
+ }
+
+ public PartitionGenerator newGenerator(StressSettings settings)
+ {
+ if (generatorFactory == null)
+ {
+ synchronized (this)
+ {
+ maybeLoadSchemaInfo(settings);
+ if (generatorFactory == null)
+ generatorFactory = new GeneratorFactory();
+ }
+ }
+
+ return generatorFactory.newGenerator();
+ }
+
+ private class GeneratorFactory
+ {
+ final List<ColumnInfo> partitionKeys = new ArrayList<>();
+ final List<ColumnInfo> clusteringColumns = new ArrayList<>();
+ final List<ColumnInfo> valueColumns = new ArrayList<>();
+
+ private GeneratorFactory()
+ {
+ Set<ColumnMetadata> keyColumns = com.google.common.collect.Sets.newHashSet(tableMetaData.getPrimaryKey());
+
+ for (ColumnMetadata metadata : tableMetaData.getPartitionKey())
+ partitionKeys.add(new ColumnInfo(metadata.getName(), metadata.getType(), columnConfigs.get(metadata.getName())));
+ for (ColumnMetadata metadata : tableMetaData.getClusteringColumns())
+ clusteringColumns.add(new ColumnInfo(metadata.getName(), metadata.getType(), columnConfigs.get(metadata.getName())));
+ for (ColumnMetadata metadata : tableMetaData.getColumns())
+ if (!keyColumns.contains(metadata))
+ valueColumns.add(new ColumnInfo(metadata.getName(), metadata.getType(), columnConfigs.get(metadata.getName())));
+ }
+
+ PartitionGenerator newGenerator()
+ {
+ return new PartitionGenerator(get(partitionKeys), get(clusteringColumns), get(valueColumns));
+ }
+
+ List<Generator> get(List<ColumnInfo> columnInfos)
+ {
+ List<Generator> result = new ArrayList<>();
+ for (ColumnInfo columnInfo : columnInfos)
+ result.add(columnInfo.getGenerator());
+ return result;
+ }
+ }
+
+ static class ColumnInfo
+ {
+ final String name;
+ final DataType type;
+ final GeneratorConfig config;
+
+ ColumnInfo(String name, DataType type, GeneratorConfig config)
+ {
+ this.name = name;
+ this.type = type;
+ this.config = config;
+ }
+
+ Generator getGenerator()
+ {
+ return getGenerator(name, type, config);
+ }
+
+ static Generator getGenerator(final String name, final DataType type, GeneratorConfig config)
+ {
+ switch (type.getName())
+ {
+ case ASCII:
+ case TEXT:
+ case VARCHAR:
+ return new Strings(name, config);
+ case BIGINT:
+ case COUNTER:
+ return new Longs(name, config);
+ case BLOB:
+ return new Bytes(name, config);
+ case BOOLEAN:
+ return new Booleans(name, config);
+ case DECIMAL:
+ case DOUBLE:
+ return new Doubles(name, config);
+ case FLOAT:
+ return new Floats(name, config);
+ case INET:
+ return new Inets(name, config);
+ case INT:
+ case VARINT:
+ return new Integers(name, config);
+ case TIMESTAMP:
+ return new Dates(name, config);
+ case UUID:
+ return new UUIDs(name, config);
+ case TIMEUUID:
+ return new TimeUUIDs(name, config);
+ case SET:
+ return new Sets(name, getGenerator(name, type.getTypeArguments().get(0), config), config);
+ case LIST:
+ return new Lists(name, getGenerator(name, type.getTypeArguments().get(0), config), config);
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+
+ public static StressProfile load(File file) throws IOError
+ {
+ try
+ {
+ byte[] profileBytes = Files.readAllBytes(Paths.get(file.toURI()));
+
+ Constructor constructor = new Constructor(StressYaml.class);
+
+ Yaml yaml = new Yaml(constructor);
+
+ StressYaml profileYaml = yaml.loadAs(new ByteArrayInputStream(profileBytes), StressYaml.class);
+
+ StressProfile profile = new StressProfile();
+ profile.init(profileYaml);
+
+ return profile;
+ }
+ catch (YAMLException | IOException | RequestValidationException e)
+ {
+ throw new IOError(e);
+ }
+ }
+
+ static <V> void lowerCase(Map<String, V> map)
+ {
+ List<Map.Entry<String, V>> reinsert = new ArrayList<>();
+ Iterator<Map.Entry<String, V>> iter = map.entrySet().iterator();
+ while (iter.hasNext())
+ {
+ Map.Entry<String, V> e = iter.next();
+ if (!e.getKey().toLowerCase().equalsIgnoreCase(e.getKey()))
+ {
+ reinsert.add(e);
+ iter.remove();
+ }
+ }
+ for (Map.Entry<String, V> e : reinsert)
+ map.put(e.getKey().toLowerCase(), e.getValue());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/StressYaml.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressYaml.java b/tools/stress/src/org/apache/cassandra/stress/StressYaml.java
new file mode 100644
index 0000000..e94fa77
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/StressYaml.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress;
+
+import java.util.List;
+import java.util.Map;
+
+public class StressYaml
+{
+ public String seed;
+ public String keyspace;
+ public String keyspace_definition;
+ public String table;
+ public String table_definition;
+
+ public List<Map<String,Object>> columnspec;
+ public Map<String,String> queries;
+ public Map<String,String> insert;
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/Distribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/Distribution.java b/tools/stress/src/org/apache/cassandra/stress/generate/Distribution.java
new file mode 100644
index 0000000..4662454
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/Distribution.java
@@ -0,0 +1,57 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.Serializable;
+
+public abstract class Distribution implements Serializable
+{
+
+ public abstract long next();
+ public abstract double nextDouble();
+ public abstract long inverseCumProb(double cumProb);
+ public abstract void setSeed(long seed);
+
+ public long maxValue()
+ {
+ return inverseCumProb(1d);
+ }
+
+ public long minValue()
+ {
+ return inverseCumProb(0d);
+ }
+
+ // approximation of the average; slightly costly to calculate, so should not be invoked frequently
+ public long average()
+ {
+ double sum = 0;
+ int count = 0;
+ for (float d = 0 ; d <= 1.0d ; d += 0.02d)
+ {
+ sum += inverseCumProb(d);
+ count += 1;
+ }
+ return (long) (sum / count);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionBoundApache.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionBoundApache.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionBoundApache.java
new file mode 100644
index 0000000..23ce3e9
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionBoundApache.java
@@ -0,0 +1,84 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.commons.math3.distribution.AbstractRealDistribution;
+
+public class DistributionBoundApache extends Distribution
+{
+
+ final AbstractRealDistribution delegate;
+ final long min, max;
+
+ public DistributionBoundApache(AbstractRealDistribution delegate, long min, long max)
+ {
+ this.delegate = delegate;
+ this.min = min;
+ this.max = max;
+ }
+
+ @Override
+ public long next()
+ {
+ return bound(min, max, delegate.sample());
+ }
+
+ public double nextDouble()
+ {
+ return boundDouble(min, max, delegate.sample());
+ }
+
+ @Override
+ public long inverseCumProb(double cumProb)
+ {
+ return bound(min, max, delegate.inverseCumulativeProbability(cumProb));
+ }
+
+ public void setSeed(long seed)
+ {
+ delegate.reseedRandomGenerator(seed);
+ }
+
+ private static long bound(long min, long max, double val)
+ {
+ long r = (long) val;
+ if ((r >= min) & (r <= max))
+ return r;
+ if (r < min)
+ return min;
+ if (r > max)
+ return max;
+ throw new IllegalStateException();
+ }
+
+ private static double boundDouble(long min, long max, double r)
+ {
+ if ((r >= min) & (r <= max))
+ return r;
+ if (r < min)
+ return min;
+ if (r > max)
+ return max;
+ throw new IllegalStateException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFactory.java
new file mode 100644
index 0000000..d0dfa89
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFactory.java
@@ -0,0 +1,31 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.Serializable;
+
+public interface DistributionFactory extends Serializable
+{
+
+ Distribution get();
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFixed.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFixed.java
new file mode 100644
index 0000000..bbfb894
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFixed.java
@@ -0,0 +1,54 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+public class DistributionFixed extends Distribution
+{
+
+ final long key;
+
+ public DistributionFixed(long key)
+ {
+ this.key = key;
+ }
+
+ @Override
+ public long next()
+ {
+ return key;
+ }
+
+ public double nextDouble()
+ {
+ return key;
+ }
+
+ @Override
+ public long inverseCumProb(double cumProb)
+ {
+ return key;
+ }
+
+ public void setSeed(long seed)
+ {
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionInverted.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionInverted.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionInverted.java
new file mode 100644
index 0000000..df52cb8
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionInverted.java
@@ -0,0 +1,37 @@
+package org.apache.cassandra.stress.generate;
+
+public class DistributionInverted extends Distribution
+{
+
+ final Distribution wrapped;
+ final long min;
+ final long max;
+
+ public DistributionInverted(Distribution wrapped)
+ {
+ this.wrapped = wrapped;
+ this.min = wrapped.minValue();
+ this.max = wrapped.maxValue();
+ }
+
+ public long next()
+ {
+ return max - (wrapped.next() - min);
+ }
+
+ public double nextDouble()
+ {
+ return max - (wrapped.nextDouble() - min);
+ }
+
+ public long inverseCumProb(double cumProb)
+ {
+ return max - (wrapped.inverseCumProb(cumProb) - min);
+ }
+
+ public void setSeed(long seed)
+ {
+ wrapped.setSeed(seed);
+ }
+
+}
[15/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java b/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java
index 2782a05..7ede496 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java
@@ -63,8 +63,10 @@ public class SmartThriftClient implements ThriftClient
return r;
r = queryIdCounter.incrementAndGet();
if (queryIds.putIfAbsent(query, r) == null)
+ {
+ queryStrings.put(r, query);
return r;
- queryStrings.put(r, query);
+ }
return queryIds.get(query);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/Timer.java b/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
index 06d113d..45e1ba7 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
@@ -43,7 +43,8 @@ public final class Timer
private int opCount;
// aggregate info
- private int keyCount;
+ private long partitionCount;
+ private long rowCount;
private long total;
private long max;
private long maxStart;
@@ -65,7 +66,7 @@ public final class Timer
return 1 + (index >>> SAMPLE_SIZE_SHIFT);
}
- public void stop(int keys)
+ public void stop(long partitionCount, long rowCount)
{
maybeReport();
long now = System.nanoTime();
@@ -79,7 +80,8 @@ public final class Timer
}
total += time;
opCount += 1;
- keyCount += keys;
+ this.partitionCount += partitionCount;
+ this.rowCount += rowCount;
upToDateAsOf = now;
}
@@ -94,11 +96,12 @@ public final class Timer
( new SampleOfLongs(Arrays.copyOf(sample, index(opCount)), p(opCount)),
new SampleOfLongs(Arrays.copyOfRange(sample, index(opCount), Math.min(opCount, sample.length)), p(opCount) - 1)
);
- final TimingInterval report = new TimingInterval(lastSnap, upToDateAsOf, max, maxStart, max, keyCount, total, opCount,
+ final TimingInterval report = new TimingInterval(lastSnap, upToDateAsOf, max, maxStart, max, partitionCount, rowCount, total, opCount,
SampleOfLongs.merge(rnd, sampleLatencies, Integer.MAX_VALUE));
// reset counters
opCount = 0;
- keyCount = 0;
+ partitionCount = 0;
+ rowCount = 0;
total = 0;
max = 0;
lastSnap = upToDateAsOf;
@@ -145,6 +148,4 @@ public final class Timer
reportRequest = null;
}
}
-
-}
-
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java b/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
index 9e68045..db3fef1 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
@@ -39,7 +39,8 @@ public final class TimingInterval
public final long totalLatency;
// discrete
- public final long keyCount;
+ public final long partitionCount;
+ public final long rowCount;
public final long operationCount;
final SampleOfLongs sample;
@@ -48,16 +49,17 @@ public final class TimingInterval
{
start = end = time;
maxLatency = totalLatency = 0;
- keyCount = operationCount = 0;
+ partitionCount = rowCount = operationCount = 0;
pauseStart = pauseLength = 0;
sample = new SampleOfLongs(new long[0], 1d);
}
- TimingInterval(long start, long end, long maxLatency, long pauseStart, long pauseLength, long keyCount, long totalLatency, long operationCount, SampleOfLongs sample)
+ TimingInterval(long start, long end, long maxLatency, long pauseStart, long pauseLength, long partitionCount, long rowCount, long totalLatency, long operationCount, SampleOfLongs sample)
{
this.start = start;
this.end = Math.max(end, start);
this.maxLatency = maxLatency;
- this.keyCount = keyCount;
+ this.partitionCount = partitionCount;
+ this.rowCount = rowCount;
this.totalLatency = totalLatency;
this.operationCount = operationCount;
this.pauseStart = pauseStart;
@@ -68,7 +70,7 @@ public final class TimingInterval
// merge multiple timer intervals together
static TimingInterval merge(Random rnd, List<TimingInterval> intervals, int maxSamples, long start)
{
- int operationCount = 0, keyCount = 0;
+ long operationCount = 0, partitionCount = 0, rowCount = 0;
long maxLatency = 0, totalLatency = 0;
List<SampleOfLongs> latencies = new ArrayList<>();
long end = 0;
@@ -79,7 +81,8 @@ public final class TimingInterval
operationCount += interval.operationCount;
maxLatency = Math.max(interval.maxLatency, maxLatency);
totalLatency += interval.totalLatency;
- keyCount += interval.keyCount;
+ partitionCount += interval.partitionCount;
+ rowCount += interval.rowCount;
latencies.addAll(Arrays.asList(interval.sample));
if (interval.pauseLength > 0)
{
@@ -89,7 +92,7 @@ public final class TimingInterval
}
if (pauseEnd < pauseStart)
pauseEnd = pauseStart = 0;
- return new TimingInterval(start, end, maxLatency, pauseStart, pauseEnd - pauseStart, keyCount, totalLatency, operationCount,
+ return new TimingInterval(start, end, maxLatency, pauseStart, pauseEnd - pauseStart, partitionCount, rowCount, totalLatency, operationCount,
SampleOfLongs.merge(rnd, latencies, maxSamples));
}
@@ -104,9 +107,14 @@ public final class TimingInterval
return operationCount / ((end - (start + pauseLength)) * 0.000000001d);
}
- public double keyRate()
+ public double partitionRate()
{
- return keyCount / ((end - start) * 0.000000001d);
+ return partitionCount / ((end - start) * 0.000000001d);
+ }
+
+ public double rowRate()
+ {
+ return rowCount / ((end - start) * 0.000000001d);
}
public double meanLatency()
[02/23] git commit: Merge branch 'cassandra-2.1.0' into cassandra-2.1
Posted by be...@apache.org.
Merge branch 'cassandra-2.1.0' into cassandra-2.1
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/4e53152c
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/4e53152c
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/4e53152c
Branch: refs/heads/trunk
Commit: 4e53152c51a08a3544cbef1bc7164b2792aa6f68
Parents: 59a8504 61ee287
Author: Sylvain Lebresne <sy...@datastax.com>
Authored: Mon Jul 7 18:22:49 2014 +0200
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Mon Jul 7 18:22:49 2014 +0200
----------------------------------------------------------------------
test/unit/org/apache/cassandra/cql3/CQLTester.java | 2 --
1 file changed, 2 deletions(-)
----------------------------------------------------------------------
[10/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionAnyProbabilities.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionAnyProbabilities.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionAnyProbabilities.java
new file mode 100644
index 0000000..a9af1bd
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionAnyProbabilities.java
@@ -0,0 +1,78 @@
+package org.apache.cassandra.stress.settings;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.math3.util.Pair;
+
+public final class OptionAnyProbabilities extends OptionMulti
+{
+ public OptionAnyProbabilities(String name, String description)
+ {
+ super(name, description, false);
+ }
+
+ final CollectRatios ratios = new CollectRatios();
+
+ private static final class CollectRatios extends Option
+ {
+ Map<String, Double> options = new LinkedHashMap<>();
+
+ boolean accept(String param)
+ {
+ String[] args = param.split("=");
+ if (args.length == 2 && args[1].length() > 0 && args[0].length() > 0)
+ {
+ if (options.put(args[0], Double.parseDouble(args[1])) != null)
+ throw new IllegalArgumentException(args[0] + " set twice");
+ return true;
+ }
+ return false;
+ }
+
+ boolean happy()
+ {
+ return !options.isEmpty();
+ }
+
+ String shortDisplay()
+ {
+ return null;
+ }
+
+ String longDisplay()
+ {
+ return null;
+ }
+
+ List<String> multiLineDisplay()
+ {
+ return Collections.emptyList();
+ }
+
+ boolean setByUser()
+ {
+ return !options.isEmpty();
+ }
+ }
+
+
+ @Override
+ public List<? extends Option> options()
+ {
+ return Arrays.asList(ratios);
+ }
+
+ List<Pair<String, Double>> ratios()
+ {
+ List<Pair<String, Double>> ratiosOut = new ArrayList<>();
+ for (Map.Entry<String, Double> e : ratios.options.entrySet())
+ ratiosOut.add(new Pair<String, Double>(e.getKey(), e.getValue()));
+ return ratiosOut;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java
deleted file mode 100644
index bde2b10..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java
+++ /dev/null
@@ -1,203 +0,0 @@
-package org.apache.cassandra.stress.settings;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.File;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.cassandra.stress.generatedata.*;
-
-/**
- * For selecting a data generator
- */
-class OptionDataGen extends Option
-{
-
- private static final Pattern FULL = Pattern.compile("([A-Z]+)\\(([^)]+)\\)", Pattern.CASE_INSENSITIVE);
- private static final Pattern ARGS = Pattern.compile("[^,]+");
-
- final String prefix;
- private DataGenFactory factory;
- private final DataGenFactory defaultFactory;
-
- public OptionDataGen(String prefix, String defaultSpec)
- {
- this.prefix = prefix;
- this.defaultFactory = defaultSpec == null ? null : get(defaultSpec);
- }
-
- @Override
- public boolean accept(String param)
- {
- if (!param.toLowerCase().startsWith(prefix))
- return false;
- factory = get(param.substring(prefix.length()));
- return true;
- }
-
- private static DataGenFactory get(String spec)
- {
- Matcher m = FULL.matcher(spec);
- if (!m.matches())
- throw new IllegalArgumentException("Illegal data generator specification: " + spec);
- String name = m.group(1);
- Impl impl = LOOKUP.get(name.toLowerCase());
- if (impl == null)
- throw new IllegalArgumentException("Illegal data generator type: " + name);
- List<String> params = new ArrayList<>();
- m = ARGS.matcher(m.group(2));
- while (m.find())
- params.add(m.group());
- return impl.getFactory(params);
- }
-
- public DataGenFactory get()
- {
- return factory != null ? factory : defaultFactory;
- }
-
- @Override
- public boolean happy()
- {
- return factory != null || defaultFactory != null;
- }
-
- public boolean setByUser()
- {
- return factory != null;
- }
-
- @Override
- public String shortDisplay()
- {
- return prefix + "ALG()";
- }
-
- public String longDisplay()
- {
- return shortDisplay() + ": Specify a data generator from:";
- }
-
- @Override
- public List<String> multiLineDisplay()
- {
- return Arrays.asList(
- GroupedOptions.formatMultiLine("RANDOM()", "Completely random byte generation"),
- GroupedOptions.formatMultiLine("REPEAT(<freq>)", "An MD5 hash of (opIndex % freq) combined with the column index"),
- GroupedOptions.formatMultiLine("DICT(<file>)","Random words from a dictionary; the file should be in the format \"<freq> <word>\"")
- );
- }
-
- private static final Map<String, Impl> LOOKUP;
- static
- {
- final Map<String, Impl> lookup = new HashMap<>();
- lookup.put("random", new RandomImpl());
- lookup.put("rand", new RandomImpl());
- lookup.put("rnd", new RandomImpl());
- lookup.put("repeat", new RepeatImpl());
- lookup.put("dict", new DictionaryImpl());
- lookup.put("dictionary", new DictionaryImpl());
- LOOKUP = lookup;
- }
-
- private static interface Impl
- {
- public DataGenFactory getFactory(List<String> params);
- }
-
- private static final class RandomImpl implements Impl
- {
- @Override
- public DataGenFactory getFactory(List<String> params)
- {
- if (params.size() != 0)
- throw new IllegalArgumentException("Invalid parameter list for random generator: " + params);
- return new RandomFactory();
- }
- }
-
- private static final class RepeatImpl implements Impl
- {
-
- @Override
- public DataGenFactory getFactory(List<String> params)
- {
- if (params.size() != 1)
- throw new IllegalArgumentException("Invalid parameter list for repeating generator: " + params);
- try
- {
- int repeatFrequency = Integer.parseInt(params.get(0));
- return new RepeatsFactory(repeatFrequency);
- } catch (Exception _)
- {
- throw new IllegalArgumentException("Invalid parameter list for repeating generator: " + params);
- }
- }
- }
-
- private static final class DictionaryImpl implements Impl
- {
-
- @Override
- public DataGenFactory getFactory(List<String> params)
- {
- if (params.size() != 1)
- throw new IllegalArgumentException("Invalid parameter list for dictionary generator: " + params);
- try
- {
- final File file = new File(params.get(0));
- return DataGenStringDictionary.getFactory(file);
- } catch (Exception e)
- {
- throw new IllegalArgumentException("Invalid parameter list for dictionary generator: " + params, e);
- }
- }
- }
-
- private static final class RandomFactory implements DataGenFactory
- {
- @Override
- public DataGen get()
- {
- return new DataGenBytesRandom();
- }
- }
-
- private static final class RepeatsFactory implements DataGenFactory
- {
- final int frequency;
- private RepeatsFactory(int frequency)
- {
- this.frequency = frequency;
- }
-
- @Override
- public DataGen get()
- {
- return new DataGenStringRepeats(frequency);
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java
----------------------------------------------------------------------
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 76fa0a9..70a85ae 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java
@@ -25,19 +25,20 @@ import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.apache.cassandra.stress.generatedata.*;
+import org.apache.cassandra.stress.generate.*;
import org.apache.commons.math3.distribution.ExponentialDistribution;
import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.commons.math3.distribution.UniformRealDistribution;
import org.apache.commons.math3.distribution.WeibullDistribution;
+import org.apache.commons.math3.random.JDKRandomGenerator;
/**
* For selecting a mathematical distribution
*/
-class OptionDistribution extends Option
+public class OptionDistribution extends Option
{
- private static final Pattern FULL = Pattern.compile("([A-Z]+)\\((.+)\\)", Pattern.CASE_INSENSITIVE);
+ private static final Pattern FULL = Pattern.compile("(~?)([A-Z]+)\\((.+)\\)", Pattern.CASE_INSENSITIVE);
private static final Pattern ARGS = Pattern.compile("[^,]+");
final String prefix;
@@ -61,20 +62,22 @@ class OptionDistribution extends Option
return true;
}
- private static DistributionFactory get(String spec)
+ public static DistributionFactory get(String spec)
{
Matcher m = FULL.matcher(spec);
if (!m.matches())
throw new IllegalArgumentException("Illegal distribution specification: " + spec);
- String name = m.group(1);
+ boolean inverse = m.group(1).equals("~");
+ String name = m.group(2);
Impl impl = LOOKUP.get(name.toLowerCase());
if (impl == null)
throw new IllegalArgumentException("Illegal distribution type: " + name);
List<String> params = new ArrayList<>();
- m = ARGS.matcher(m.group(2));
+ m = ARGS.matcher(m.group(3));
while (m.find())
params.add(m.group());
- return impl.getFactory(params);
+ DistributionFactory factory = impl.getFactory(params);
+ return inverse ? new InverseFactory(factory) : factory;
}
public DistributionFactory get()
@@ -103,6 +106,7 @@ class OptionDistribution extends Option
GroupedOptions.formatMultiLine("GAUSSIAN(min..max,mean,stdev)", "A gaussian/normal distribution, with explicitly defined mean and stdev"),
GroupedOptions.formatMultiLine("UNIFORM(min..max)", "A uniform distribution over the range [min, max]"),
GroupedOptions.formatMultiLine("FIXED(val)", "A fixed distribution, always returning the same value"),
+ "Preceding the name with ~ will invert the distribution, e.g. ~exp(1..10) will yield 10 most, instead of least, often",
"Aliases: extr, gauss, normal, norm, weibull"
);
}
@@ -142,6 +146,23 @@ class OptionDistribution extends Option
public DistributionFactory getFactory(List<String> params);
}
+ public static long parseLong(String value)
+ {
+ long multiplier = 1;
+ value = value.trim().toLowerCase();
+ switch (value.charAt(value.length() - 1))
+ {
+ case 'b':
+ multiplier *= 1000;
+ case 'm':
+ multiplier *= 1000;
+ case 'k':
+ multiplier *= 1000;
+ value = value.substring(0, value.length() - 1);
+ }
+ return Long.parseLong(value) * multiplier;
+ }
+
private static final class GaussianImpl implements Impl
{
@@ -153,8 +174,8 @@ class OptionDistribution extends Option
try
{
String[] bounds = params.get(0).split("\\.\\.+");
- final long min = Long.parseLong(bounds[0]);
- final long max = Long.parseLong(bounds[1]);
+ final long min = parseLong(bounds[0]);
+ final long max = parseLong(bounds[1]);
final double mean, stdev;
if (params.size() == 3)
{
@@ -185,8 +206,8 @@ class OptionDistribution extends Option
try
{
String[] bounds = params.get(0).split("\\.\\.+");
- final long min = Long.parseLong(bounds[0]);
- final long max = Long.parseLong(bounds[1]);
+ final long min = parseLong(bounds[0]);
+ final long max = parseLong(bounds[1]);
ExponentialDistribution findBounds = new ExponentialDistribution(1d);
// max probability should be roughly equal to accuracy of (max-min) to ensure all values are visitable,
// over entire range, but this results in overly skewed distribution, so take sqrt
@@ -209,8 +230,8 @@ class OptionDistribution extends Option
try
{
String[] bounds = params.get(0).split("\\.\\.+");
- final long min = Long.parseLong(bounds[0]);
- final long max = Long.parseLong(bounds[1]);
+ final long min = parseLong(bounds[0]);
+ final long max = parseLong(bounds[1]);
final double shape = Double.parseDouble(params.get(1));
WeibullDistribution findBounds = new WeibullDistribution(shape, 1d);
// max probability should be roughly equal to accuracy of (max-min) to ensure all values are visitable,
@@ -235,8 +256,8 @@ class OptionDistribution extends Option
try
{
String[] bounds = params.get(0).split("\\.\\.+");
- final long min = Long.parseLong(bounds[0]);
- final long max = Long.parseLong(bounds[1]);
+ final long min = parseLong(bounds[0]);
+ final long max = parseLong(bounds[1]);
return new UniformFactory(min, max);
} catch (Exception _)
{
@@ -255,7 +276,7 @@ class OptionDistribution extends Option
throw new IllegalArgumentException("Invalid parameter list for uniform distribution: " + params);
try
{
- final long key = Long.parseLong(params.get(0));
+ final long key = parseLong(params.get(0));
return new FixedFactory(key);
} catch (Exception _)
{
@@ -264,6 +285,20 @@ class OptionDistribution extends Option
}
}
+ private static final class InverseFactory implements DistributionFactory
+ {
+ final DistributionFactory wrapped;
+ private InverseFactory(DistributionFactory wrapped)
+ {
+ this.wrapped = wrapped;
+ }
+
+ public Distribution get()
+ {
+ return new DistributionInverted(wrapped.get());
+ }
+ }
+
// factories
private static final class ExpFactory implements DistributionFactory
@@ -280,7 +315,7 @@ class OptionDistribution extends Option
@Override
public Distribution get()
{
- return new DistributionOffsetApache(new ExponentialDistribution(mean), min, max);
+ return new DistributionOffsetApache(new ExponentialDistribution(new JDKRandomGenerator(), mean, ExponentialDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY), min, max);
}
}
@@ -299,7 +334,7 @@ class OptionDistribution extends Option
@Override
public Distribution get()
{
- return new DistributionOffsetApache(new WeibullDistribution(shape, scale), min, max);
+ return new DistributionOffsetApache(new WeibullDistribution(new JDKRandomGenerator(), shape, scale, WeibullDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY), min, max);
}
}
@@ -318,7 +353,7 @@ class OptionDistribution extends Option
@Override
public Distribution get()
{
- return new DistributionBoundApache(new NormalDistribution(mean, stdev), min, max);
+ return new DistributionBoundApache(new NormalDistribution(new JDKRandomGenerator(), mean, stdev, NormalDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY), min, max);
}
}
@@ -334,7 +369,7 @@ class OptionDistribution extends Option
@Override
public Distribution get()
{
- return new DistributionBoundApache(new UniformRealDistribution(min, max + 1), min, max);
+ return new DistributionBoundApache(new UniformRealDistribution(new JDKRandomGenerator(), min, max + 1), min, max);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionEnumProbabilities.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionEnumProbabilities.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionEnumProbabilities.java
new file mode 100644
index 0000000..88ebd34
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionEnumProbabilities.java
@@ -0,0 +1,62 @@
+package org.apache.cassandra.stress.settings;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math3.util.Pair;
+
+public final class OptionEnumProbabilities<T> extends OptionMulti
+{
+ final List<OptMatcher<T>> options;
+
+ public static class Opt<T>
+ {
+ final T option;
+ final String defaultValue;
+
+ public Opt(T option, String defaultValue)
+ {
+ this.option = option;
+ this.defaultValue = defaultValue;
+ }
+ }
+
+ private static final class OptMatcher<T> extends OptionSimple
+ {
+ final T opt;
+ OptMatcher(T opt, String defaultValue)
+ {
+ super(opt.toString().toLowerCase() + "=", "[0-9]+(\\.[0-9]+)?", defaultValue, "Performs this many " + opt + " operations out of total", false);
+ this.opt = opt;
+ }
+ }
+
+ public OptionEnumProbabilities(List<Opt<T>> universe, String name, String description)
+ {
+ super(name, description, false);
+ List<OptMatcher<T>> options = new ArrayList<>();
+ for (Opt<T> option : universe)
+ options.add(new OptMatcher<T>(option.option, option.defaultValue));
+ this.options = options;
+ }
+
+ @Override
+ public List<? extends Option> options()
+ {
+ return options;
+ }
+
+ List<Pair<T, Double>> ratios()
+ {
+ List<? extends Option> ratiosIn = setByUser() ? optionsSetByUser() : defaultOptions();
+ List<Pair<T, Double>> ratiosOut = new ArrayList<>();
+ for (Option opt : ratiosIn)
+ {
+ OptMatcher<T> optMatcher = (OptMatcher<T>) opt;
+ double d = Double.parseDouble(optMatcher.value());
+ ratiosOut.add(new Pair<>(optMatcher.opt, d));
+ }
+ return ratiosOut;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java
----------------------------------------------------------------------
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 60faad8..32bfc65 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java
@@ -156,7 +156,8 @@ abstract class OptionMulti extends Option
String[] args = param.split("=");
if (args.length == 2 && args[1].length() > 0 && args[0].length() > 0)
{
- options.put(args[0], args[1]);
+ if (options.put(args[0], args[1]) != null)
+ throw new IllegalArgumentException(args[0] + " set twice");
return true;
}
return false;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionRatioDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionRatioDistribution.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionRatioDistribution.java
new file mode 100644
index 0000000..2459c20
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionRatioDistribution.java
@@ -0,0 +1,166 @@
+package org.apache.cassandra.stress.settings;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.math3.distribution.ExponentialDistribution;
+import org.apache.commons.math3.distribution.NormalDistribution;
+import org.apache.commons.math3.distribution.UniformRealDistribution;
+import org.apache.commons.math3.distribution.WeibullDistribution;
+import org.apache.commons.math3.random.JDKRandomGenerator;
+
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionBoundApache;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.DistributionFixed;
+import org.apache.cassandra.stress.generate.DistributionInverted;
+import org.apache.cassandra.stress.generate.DistributionOffsetApache;
+import org.apache.cassandra.stress.generate.RatioDistribution;
+import org.apache.cassandra.stress.generate.RatioDistributionFactory;
+
+/**
+ * For selecting a mathematical distribution
+ */
+public class OptionRatioDistribution extends Option
+{
+
+ private static final Pattern FULL = Pattern.compile("(.*)/([0-9]+[KMB]?)", Pattern.CASE_INSENSITIVE);
+
+ final OptionDistribution delegate;
+ private double divisor;
+
+ private static final RatioDistribution DEFAULT = new RatioDistribution(new DistributionFixed(1), 1);
+
+ public OptionRatioDistribution(String prefix, String defaultSpec, String description)
+ {
+ delegate = new OptionDistribution(prefix, defaultSpec, description);
+ }
+
+ @Override
+ public boolean accept(String param)
+ {
+ Matcher m = FULL.matcher(param);
+ if (!m.matches() || !delegate.accept(m.group(1)))
+ return false;
+ divisor = OptionDistribution.parseLong(m.group(2));
+ return true;
+ }
+
+ public static RatioDistributionFactory get(String spec)
+ {
+ OptionRatioDistribution opt = new OptionRatioDistribution("", "", "");
+ if (!opt.accept(spec))
+ throw new IllegalArgumentException();
+ return opt.get();
+ }
+
+ public RatioDistributionFactory get()
+ {
+ return !delegate.setByUser() ? new DefaultFactory() : new DelegateFactory(delegate.get(), divisor);
+ }
+
+ @Override
+ public boolean happy()
+ {
+ return delegate.happy();
+ }
+
+ public String longDisplay()
+ {
+ return delegate.longDisplay();
+ }
+
+ @Override
+ public List<String> multiLineDisplay()
+ {
+ return Arrays.asList(
+ GroupedOptions.formatMultiLine("EXP(min..max)/divisor", "An exponential ratio distribution over the range [min..max]/divisor"),
+ GroupedOptions.formatMultiLine("EXTREME(min..max,shape)/divisor", "An extreme value (Weibull) ratio distribution over the range [min..max]/divisor"),
+ GroupedOptions.formatMultiLine("GAUSSIAN(min..max,stdvrng)/divisor", "A gaussian/normal ratio distribution, where mean=(min+max)/2, and stdev is ((mean-min)/stdvrng)/divisor"),
+ GroupedOptions.formatMultiLine("GAUSSIAN(min..max,mean,stdev)/divisor", "A gaussian/normal ratio distribution, with explicitly defined mean and stdev"),
+ GroupedOptions.formatMultiLine("UNIFORM(min..max)/divisor", "A uniform ratio distribution over the range [min, max]/divisor"),
+ GroupedOptions.formatMultiLine("FIXED(val)/divisor", "A fixed ratio distribution, always returning the same value"),
+ "Preceding the name with ~ will invert the distribution, e.g. ~exp(1..10)/10 will yield 0.1 least, instead of most, often",
+ "Aliases: extr, gauss, normal, norm, weibull"
+ );
+ }
+
+ boolean setByUser()
+ {
+ return delegate.setByUser();
+ }
+
+ @Override
+ public String shortDisplay()
+ {
+ return delegate.shortDisplay();
+ }
+
+ // factories
+
+ private static final class DefaultFactory implements RatioDistributionFactory
+ {
+ @Override
+ public RatioDistribution get()
+ {
+ return DEFAULT;
+ }
+ }
+
+ private static final class DelegateFactory implements RatioDistributionFactory
+ {
+ final DistributionFactory delegate;
+ final double divisor;
+
+ private DelegateFactory(DistributionFactory delegate, double divisor)
+ {
+ this.delegate = delegate;
+ this.divisor = divisor;
+ }
+
+ @Override
+ public RatioDistribution get()
+ {
+ return new RatioDistribution(delegate.get(), divisor);
+ }
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object that)
+ {
+ return super.equals(that) && ((OptionRatioDistribution) that).delegate.equals(this.delegate);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java
index 9365e45..71c1ffe 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java
@@ -21,6 +21,7 @@ package org.apache.cassandra.stress.settings;
*/
+import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
@@ -30,7 +31,7 @@ import com.google.common.base.Function;
/**
* For parsing a simple (sub)option for a command/major option
*/
-class OptionSimple extends Option
+class OptionSimple extends Option implements Serializable
{
final String displayPrefix;
@@ -41,7 +42,7 @@ class OptionSimple extends Option
private final boolean required;
private String value;
- private static final class ValueMatcher implements Function<String, String>
+ private static final class ValueMatcher implements Function<String, String>, Serializable
{
final Pattern pattern;
private ValueMatcher(Pattern pattern)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
index 7e20ec6..04c2a47 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
@@ -23,13 +23,15 @@ package org.apache.cassandra.stress.settings;
import java.io.Serializable;
import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.cassandra.db.marshal.*;
-import org.apache.cassandra.stress.generatedata.*;
+import org.apache.cassandra.stress.generate.*;
import org.apache.cassandra.utils.ByteBufferUtil;
/**
@@ -39,17 +41,13 @@ public class SettingsColumn implements Serializable
{
public final int maxColumnsPerKey;
- public final List<ByteBuffer> names;
+ public transient final List<ByteBuffer> names;
public final List<String> namestrs;
public final String comparator;
- public final boolean useTimeUUIDComparator;
- public final int superColumns;
- public final boolean useSuperColumns;
public final boolean variableColumnCount;
public final boolean slice;
- private final DistributionFactory sizeDistribution;
- private final DistributionFactory countDistribution;
- private final DataGenFactory dataGenFactory;
+ public final DistributionFactory sizeDistribution;
+ public final DistributionFactory countDistribution;
public SettingsColumn(GroupedOptions options)
{
@@ -62,9 +60,6 @@ public class SettingsColumn implements Serializable
public SettingsColumn(Options options, NameOptions name, CountOptions count)
{
sizeDistribution = options.size.get();
- superColumns = Integer.parseInt(options.superColumns.value());
- dataGenFactory = options.generator.get();
- useSuperColumns = superColumns > 0;
{
comparator = options.comparator.value();
AbstractType parsed = null;
@@ -79,8 +74,6 @@ public class SettingsColumn implements Serializable
System.exit(1);
}
- useTimeUUIDComparator = parsed instanceof TimeUUIDType;
-
if (!(parsed instanceof TimeUUIDType || parsed instanceof AsciiType || parsed instanceof UTF8Type))
{
System.err.println("Currently supported types are: TimeUUIDType, AsciiType, UTF8Type.");
@@ -102,10 +95,13 @@ public class SettingsColumn implements Serializable
final String[] names = name.name.value().split(",");
this.names = new ArrayList<>(names.length);
- this.namestrs = Arrays.asList(names);
for (String columnName : names)
this.names.add(comparator.fromString(columnName));
+ Collections.sort(this.names, BytesType.instance);
+ this.namestrs = new ArrayList<>();
+ for (ByteBuffer columnName : this.names)
+ this.namestrs.add(comparator.getString(columnName));
final int nameCount = this.names.size();
countDistribution = new DistributionFactory()
@@ -123,23 +119,24 @@ public class SettingsColumn implements Serializable
ByteBuffer[] names = new ByteBuffer[(int) countDistribution.get().maxValue()];
String[] namestrs = new String[(int) countDistribution.get().maxValue()];
for (int i = 0 ; i < names.length ; i++)
- {
names[i] = ByteBufferUtil.bytes("C" + i);
- namestrs[i] = "C" + i;
+ Arrays.sort(names, BytesType.instance);
+ try
+ {
+ for (int i = 0 ; i < names.length ; i++)
+ namestrs[i] = ByteBufferUtil.string(names[i]);
+ }
+ catch (CharacterCodingException e)
+ {
+ throw new RuntimeException(e);
}
+
this.names = Arrays.asList(names);
this.namestrs = Arrays.asList(namestrs);
}
maxColumnsPerKey = (int) countDistribution.get().maxValue();
variableColumnCount = countDistribution.get().minValue() < maxColumnsPerKey;
- // TODO: should warn that we always slice for useTimeUUIDComparator?
- slice = options.slice.setByUser() || useTimeUUIDComparator;
- // TODO: with useTimeUUIDCOmparator, should we still try to select a random start for reads if possible?
- }
-
- public RowGen newRowGen()
- {
- return new RowGenDistributedSize(dataGenFactory.get(), countDistribution.get(), sizeDistribution.get());
+ slice = options.slice.setByUser();
}
// Option Declarations
@@ -150,7 +147,6 @@ public class SettingsColumn implements Serializable
final OptionSimple comparator = new OptionSimple("comparator=", "TimeUUIDType|AsciiType|UTF8Type", "AsciiType", "Column Comparator to use", false);
final OptionSimple slice = new OptionSimple("slice", "", null, "If set, range slices will be used for reads, otherwise a names query will be", false);
final OptionDistribution size = new OptionDistribution("size=", "FIXED(34)", "Cell size distribution");
- final OptionDataGen generator = new OptionDataGen("data=", "REPEAT(50)");
}
private static final class NameOptions extends Options
@@ -160,7 +156,7 @@ public class SettingsColumn implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(name, slice, superColumns, comparator, size, generator);
+ return Arrays.asList(name, slice, superColumns, comparator, size);
}
}
@@ -171,7 +167,7 @@ public class SettingsColumn implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(count, slice, superColumns, comparator, size, generator);
+ return Arrays.asList(count, slice, superColumns, comparator, size);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
index b491707..032f00c 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
@@ -26,23 +26,24 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import org.apache.cassandra.stress.generatedata.DistributionFactory;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
import org.apache.cassandra.thrift.ConsistencyLevel;
// Generic command settings - common to read/write/etc
-public class SettingsCommand implements Serializable
+public abstract class SettingsCommand implements Serializable
{
public final Command type;
public final long count;
public final int tries;
public final boolean ignoreErrors;
+ public final boolean noWarmup;
public final ConsistencyLevel consistencyLevel;
public final double targetUncertainty;
public final int minimumUncertaintyMeasurements;
public final int maximumUncertaintyMeasurements;
- public final DistributionFactory add;
- public final int keysAtOnce;
+
+ public abstract OpDistributionFactory getFactory(StressSettings settings);
public SettingsCommand(Command type, GroupedOptions options)
{
@@ -58,8 +59,7 @@ public class SettingsCommand implements Serializable
this.tries = Math.max(1, Integer.parseInt(options.retries.value()) + 1);
this.ignoreErrors = options.ignoreErrors.setByUser();
this.consistencyLevel = ConsistencyLevel.valueOf(options.consistencyLevel.value().toUpperCase());
- this.keysAtOnce = Integer.parseInt(options.atOnce.value());
- this.add = options.add.get();
+ this.noWarmup = options.noWarmup.setByUser();
if (count != null)
{
this.count = Long.parseLong(count.count.value());
@@ -82,8 +82,8 @@ public class SettingsCommand implements Serializable
{
final OptionSimple retries = new OptionSimple("tries=", "[0-9]+", "9", "Number of tries to perform for each operation before failing", false);
final OptionSimple ignoreErrors = new OptionSimple("ignore_errors", "", null, "Do not print/log errors", false);
+ final OptionSimple noWarmup = new OptionSimple("no_warmup", "", null, "Do not warmup the process", false);
final OptionSimple consistencyLevel = new OptionSimple("cl=", "ONE|QUORUM|LOCAL_QUORUM|EACH_QUORUM|ALL|ANY", "ONE", "Consistency level to use", false);
- final OptionDistribution add = new OptionDistribution("add=", "fixed(1)", "Distribution of value of counter increments");
final OptionSimple atOnce = new OptionSimple("at-once=", "[0-9]+", "1000", "Number of keys per operation for multiget", false);
}
@@ -93,7 +93,7 @@ public class SettingsCommand implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(count, retries, ignoreErrors, consistencyLevel, add, atOnce);
+ return Arrays.asList(count, retries, noWarmup, ignoreErrors, consistencyLevel, atOnce);
}
}
@@ -105,7 +105,7 @@ public class SettingsCommand implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(uncertainty, minMeasurements, maxMeasurements, retries, ignoreErrors, consistencyLevel, add, atOnce);
+ return Arrays.asList(uncertainty, minMeasurements, maxMeasurements, retries, noWarmup, ignoreErrors, consistencyLevel, atOnce);
}
}
@@ -127,48 +127,16 @@ public class SettingsCommand implements Serializable
switch (cmd.category)
{
case BASIC:
- case MULTI:
- return build(cmd, params);
+ return SettingsCommandPreDefined.build(cmd, params);
case MIXED:
- return SettingsCommandMixed.build(params);
+ return SettingsCommandPreDefinedMixed.build(params);
+ case USER:
+ return SettingsCommandUser.build(params);
}
}
}
return null;
}
- static SettingsCommand build(Command type, String[] params)
- {
- GroupedOptions options = GroupedOptions.select(params, new Count(), new Uncertainty());
- if (options == null)
- {
- printHelp(type);
- System.out.println("Invalid " + type + " options provided, see output for valid options");
- System.exit(1);
- }
- return new SettingsCommand(type, options);
- }
-
- static void printHelp(Command type)
- {
- printHelp(type.toString().toLowerCase());
- }
-
- static void printHelp(String type)
- {
- GroupedOptions.printOptions(System.out, type.toLowerCase(), new Uncertainty(), new Count());
- }
-
- static Runnable helpPrinter(final Command type)
- {
- return new Runnable()
- {
- @Override
- public void run()
- {
- printHelp(type);
- }
- };
- }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMixed.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMixed.java
deleted file mode 100644
index 3f16425..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMixed.java
+++ /dev/null
@@ -1,207 +0,0 @@
-package org.apache.cassandra.stress.settings;
-/*
- *
- * 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.
- *
- */
-
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.cassandra.stress.generatedata.Distribution;
-import org.apache.cassandra.stress.generatedata.DistributionFactory;
-
-import org.apache.commons.math3.distribution.EnumeratedDistribution;
-import org.apache.commons.math3.util.Pair;
-
-// Settings unique to the mixed command type
-public class SettingsCommandMixed extends SettingsCommand
-{
-
- // Ratios for selecting commands - index for each Command, NaN indicates the command is not requested
- private final List<Pair<Command, Double>> ratios;
- private final DistributionFactory clustering;
-
- public SettingsCommandMixed(Options options)
- {
- super(Command.MIXED, options.parent);
-
- clustering = options.clustering.get();
- ratios = options.probabilities.ratios();
- if (ratios.size() == 0)
- throw new IllegalArgumentException("Must specify at least one command with a non-zero ratio");
- }
-
- public List<Command> getCommands()
- {
- final List<Command> r = new ArrayList<>();
- for (Pair<Command, Double> p : ratios)
- r.add(p.getFirst());
- return r;
- }
-
- public CommandSelector selector()
- {
- return new CommandSelector(ratios, clustering.get());
- }
-
- // Class for randomly selecting the next command type
-
- public static final class CommandSelector
- {
-
- final EnumeratedDistribution<Command> selector;
- final Distribution count;
- private Command cur;
- private long remaining;
-
- public CommandSelector(List<Pair<Command, Double>> ratios, Distribution count)
- {
- selector = new EnumeratedDistribution<>(ratios);
- this.count = count;
- }
-
- public Command next()
- {
- while (remaining == 0)
- {
- remaining = count.next();
- cur = selector.sample();
- }
- remaining--;
- return cur;
- }
- }
-
- // Option Declarations
-
- static final class Probabilities extends OptionMulti
- {
- // entry for each in Command.values()
- final OptionSimple[] ratios;
- final List<OptionSimple> grouping;
-
- public Probabilities()
- {
- super("ratio", "Specify the ratios for operations to perform; e.g. (reads=2,writes=1) will perform 2 reads for each write", false);
- OptionSimple[] ratios = new OptionSimple[Command.values().length];
- List<OptionSimple> grouping = new ArrayList<>();
- for (Command command : Command.values())
- {
- if (command.category == null)
- continue;
- String defaultValue;
- switch (command)
- {
- case MIXED:
- continue;
- case READ:
- case WRITE:
- defaultValue = "1";
- break;
- default:
- defaultValue = null;
- }
- OptionSimple ratio = new OptionSimple(command.toString().toLowerCase() +
- "=", "[0-9]+(\\.[0-9]+)?", defaultValue, "Performs this many " + command + " operations out of total", false);
- ratios[command.ordinal()] = ratio;
- grouping.add(ratio);
- }
- this.grouping = grouping;
- this.ratios = ratios;
- }
-
- @Override
- public List<? extends Option> options()
- {
- return grouping;
- }
-
- List<Pair<Command, Double>> ratios()
- {
- List<? extends Option> ratiosIn = setByUser() ? optionsSetByUser() : defaultOptions();
- List<Pair<Command, Double>> ratiosOut = new ArrayList<>();
- for (Option opt : ratiosIn)
- {
- OptionSimple ratioIn = (OptionSimple) opt;
- Command command = Command.get(ratioIn.displayPrefix.substring(0, ratioIn.displayPrefix.length() - 1));
- double d = Double.parseDouble(ratioIn.value());
- ratiosOut.add(new Pair<>(command, d));
- }
- return ratiosOut;
- }
- }
-
- static final class Options extends GroupedOptions
- {
- final SettingsCommand.Options parent;
- protected Options(SettingsCommand.Options parent)
- {
- this.parent = parent;
- }
- final OptionDistribution clustering = new OptionDistribution("clustering=", "GAUSSIAN(1..10)", "Distribution clustering runs of operations of the same kind");
- final Probabilities probabilities = new Probabilities();
-
- @Override
- public List<? extends Option> options()
- {
- final List<Option> options = new ArrayList<>();
- options.add(clustering);
- options.add(probabilities);
- options.addAll(parent.options());
- return options;
- }
-
- }
-
- // CLI utility methods
-
- public static SettingsCommandMixed build(String[] params)
- {
- GroupedOptions options = GroupedOptions.select(params,
- new Options(new SettingsCommand.Uncertainty()),
- new Options(new SettingsCommand.Count()));
- if (options == null)
- {
- printHelp();
- System.out.println("Invalid MIXED options provided, see output for valid options");
- System.exit(1);
- }
- return new SettingsCommandMixed((Options) options);
- }
-
- public static void printHelp()
- {
- GroupedOptions.printOptions(System.out, "mixed",
- new Options(new SettingsCommand.Uncertainty()),
- new Options(new SettingsCommand.Count()));
- }
-
- public static Runnable helpPrinter()
- {
- return new Runnable()
- {
- @Override
- public void run()
- {
- printHelp();
- }
- };
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
new file mode 100644
index 0000000..ac113d1
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
@@ -0,0 +1,145 @@
+package org.apache.cassandra.stress.settings;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.values.Bytes;
+import org.apache.cassandra.stress.generate.values.Generator;
+import org.apache.cassandra.stress.generate.values.GeneratorConfig;
+import org.apache.cassandra.stress.generate.values.HexBytes;
+import org.apache.cassandra.stress.operations.FixedOpDistribution;
+import org.apache.cassandra.stress.operations.OpDistribution;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
+import org.apache.cassandra.stress.operations.predefined.PredefinedOperation;
+import org.apache.cassandra.stress.util.Timer;
+
+// Settings unique to the mixed command type
+public class SettingsCommandPreDefined extends SettingsCommand
+{
+
+ public final DistributionFactory add;
+
+ public OpDistributionFactory getFactory(final StressSettings settings)
+ {
+ return new OpDistributionFactory()
+ {
+ public OpDistribution get(Timer timer)
+ {
+ return new FixedOpDistribution(PredefinedOperation.operation(type, timer, newGenerator(settings), settings, add));
+ }
+
+ public String desc()
+ {
+ return type.toString();
+ }
+
+ public Iterable<OpDistributionFactory> each()
+ {
+ return Collections.<OpDistributionFactory>singleton(this);
+ }
+ };
+ }
+
+ PartitionGenerator newGenerator(StressSettings settings)
+ {
+ List<String> names = settings.columns.namestrs;
+ List<Generator> partitionKey = Collections.<Generator>singletonList(new HexBytes("key",
+ new GeneratorConfig("randomstrkey", null,
+ OptionDistribution.get("fixed(" + settings.keys.keySize + ")"), null)));
+
+ List<Generator> columns = new ArrayList<>();
+ for (int i = 0 ; i < settings.columns.maxColumnsPerKey ; i++)
+ columns.add(new Bytes(names.get(i), new GeneratorConfig("randomstr" + names.get(i), null, settings.columns.sizeDistribution, null)));
+ return new PartitionGenerator(partitionKey, Collections.<Generator>emptyList(), columns);
+ }
+
+ public SettingsCommandPreDefined(Command type, Options options)
+ {
+ super(type, options.parent);
+ add = options.add.get();
+ }
+
+ // Option Declarations
+
+ static class Options extends GroupedOptions
+ {
+ final SettingsCommand.Options parent;
+ protected Options(SettingsCommand.Options parent)
+ {
+ this.parent = parent;
+ }
+ final OptionDistribution add = new OptionDistribution("add=", "fixed(1)", "Distribution of value of counter increments");
+
+ @Override
+ public List<? extends Option> options()
+ {
+ final List<Option> options = new ArrayList<>();
+ options.addAll(parent.options());
+ options.add(add);
+ return options;
+ }
+
+ }
+
+ // CLI utility methods
+
+ public static SettingsCommandPreDefined build(Command type, String[] params)
+ {
+ GroupedOptions options = GroupedOptions.select(params,
+ new Options(new Uncertainty()),
+ new Options(new Count()));
+ if (options == null)
+ {
+ printHelp(type);
+ System.out.println("Invalid " + type + " options provided, see output for valid options");
+ System.exit(1);
+ }
+ return new SettingsCommandPreDefined(type, (Options) options);
+ }
+
+ static void printHelp(Command type)
+ {
+ printHelp(type.toString().toLowerCase());
+ }
+
+ static void printHelp(String type)
+ {
+ GroupedOptions.printOptions(System.out, type.toLowerCase(), new Uncertainty(), new Count());
+ }
+
+ static Runnable helpPrinter(final Command type)
+ {
+ return new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ printHelp(type);
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
new file mode 100644
index 0000000..e5d4f80
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
@@ -0,0 +1,151 @@
+package org.apache.cassandra.stress.settings;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
+import org.apache.cassandra.stress.operations.SampledOpDistributionFactory;
+import org.apache.cassandra.stress.operations.predefined.PredefinedOperation;
+import org.apache.cassandra.stress.util.Timer;
+
+import org.apache.commons.math3.util.Pair;
+
+// Settings unique to the mixed command type
+public class SettingsCommandPreDefinedMixed extends SettingsCommandPreDefined
+{
+
+ // Ratios for selecting commands - index for each Command, NaN indicates the command is not requested
+ private final List<Pair<Command, Double>> ratios;
+ private final DistributionFactory clustering;
+
+ public SettingsCommandPreDefinedMixed(Options options)
+ {
+ super(Command.MIXED, options);
+
+ clustering = options.clustering.get();
+ ratios = options.probabilities.ratios();
+ if (ratios.size() == 0)
+ throw new IllegalArgumentException("Must specify at least one command with a non-zero ratio");
+ }
+
+ public OpDistributionFactory getFactory(final StressSettings settings)
+ {
+ return new SampledOpDistributionFactory<Command>(ratios, clustering)
+ {
+ protected Operation get(Timer timer, PartitionGenerator generator, Command key)
+ {
+ return PredefinedOperation.operation(key, timer, generator, settings, add);
+ }
+
+ protected PartitionGenerator newGenerator()
+ {
+ return SettingsCommandPreDefinedMixed.this.newGenerator(settings);
+ }
+ };
+ }
+
+ // Option Declarations
+
+ static class Options extends SettingsCommandPreDefined.Options
+ {
+ static List<OptionEnumProbabilities.Opt<Command>> probabilityOptions = new ArrayList<>();
+ static
+ {
+ for (Command command : Command.values())
+ {
+ if (command.category == null)
+ continue;
+ String defaultValue;
+ switch (command)
+ {
+ case MIXED:
+ continue;
+ case READ:
+ case WRITE:
+ defaultValue = "1";
+ break;
+ default:
+ defaultValue = null;
+ }
+ probabilityOptions.add(new OptionEnumProbabilities.Opt<>(command, defaultValue));
+ }
+ }
+
+ protected Options(SettingsCommand.Options parent)
+ {
+ super(parent);
+ }
+ final OptionDistribution clustering = new OptionDistribution("clustering=", "GAUSSIAN(1..10)", "Distribution clustering runs of operations of the same kind");
+ final OptionEnumProbabilities probabilities = new OptionEnumProbabilities<>(probabilityOptions, "ratio", "Specify the ratios for operations to perform; e.g. (read=2,write=1) will perform 2 reads for each write");
+
+ @Override
+ public List<? extends Option> options()
+ {
+ final List<Option> options = new ArrayList<>();
+ options.add(clustering);
+ options.add(probabilities);
+ options.addAll(super.options());
+ return options;
+ }
+
+ }
+
+ // CLI utility methods
+
+ public static SettingsCommandPreDefinedMixed build(String[] params)
+ {
+ GroupedOptions options = GroupedOptions.select(params,
+ new Options(new SettingsCommand.Uncertainty()),
+ new Options(new SettingsCommand.Count()));
+ if (options == null)
+ {
+ printHelp();
+ System.out.println("Invalid MIXED options provided, see output for valid options");
+ System.exit(1);
+ }
+ return new SettingsCommandPreDefinedMixed((Options) options);
+ }
+
+ public static void printHelp()
+ {
+ GroupedOptions.printOptions(System.out, "mixed",
+ new Options(new SettingsCommand.Uncertainty()),
+ new Options(new SettingsCommand.Count()));
+ }
+
+ public static Runnable helpPrinter()
+ {
+ return new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ printHelp();
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
new file mode 100644
index 0000000..f36296e
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
@@ -0,0 +1,135 @@
+package org.apache.cassandra.stress.settings;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math3.util.Pair;
+
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.StressProfile;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
+import org.apache.cassandra.stress.operations.SampledOpDistributionFactory;
+import org.apache.cassandra.stress.util.Timer;
+
+// Settings unique to the mixed command type
+public class SettingsCommandUser extends SettingsCommand
+{
+
+ // Ratios for selecting commands - index for each Command, NaN indicates the command is not requested
+ private final List<Pair<String, Double>> ratios;
+ private final DistributionFactory clustering;
+ public final StressProfile profile;
+
+ public SettingsCommandUser(Options options)
+ {
+ super(Command.USER, options.parent);
+
+ clustering = options.clustering.get();
+ ratios = options.ops.ratios();
+ profile = StressProfile.load(new File(options.profile.value()));
+
+ if (ratios.size() == 0)
+ throw new IllegalArgumentException("Must specify at least one command with a non-zero ratio");
+ }
+
+ public OpDistributionFactory getFactory(final StressSettings settings)
+ {
+ return new SampledOpDistributionFactory<String>(ratios, clustering)
+ {
+ protected Operation get(Timer timer, PartitionGenerator generator, String key)
+ {
+ if (key.equalsIgnoreCase("insert"))
+ return profile.getInsert(timer, generator, settings);
+ return profile.getQuery(key, timer, generator, settings);
+ }
+
+ protected PartitionGenerator newGenerator()
+ {
+ return profile.newGenerator(settings);
+ }
+ };
+ }
+
+ static final class Options extends GroupedOptions
+ {
+ final SettingsCommand.Options parent;
+ protected Options(SettingsCommand.Options parent)
+ {
+ this.parent = parent;
+ }
+ final OptionDistribution clustering = new OptionDistribution("clustering=", "GAUSSIAN(1..10)", "Distribution clustering runs of operations of the same kind");
+ final OptionSimple profile = new OptionSimple("profile=", ".*", null, "Specify the path to a yaml cql3 profile", false);
+ final OptionAnyProbabilities ops = new OptionAnyProbabilities("ops", "Specify the ratios for inserts/queries to perform; e.g. ops(insert=2,<query1>=1) will perform 2 inserts for each query1");
+
+ @Override
+ public List<? extends Option> options()
+ {
+ final List<Option> options = new ArrayList<>();
+ options.add(clustering);
+ options.add(ops);
+ options.add(profile);
+ options.addAll(parent.options());
+ return options;
+ }
+
+ }
+
+ // CLI utility methods
+
+ public static SettingsCommandUser build(String[] params)
+ {
+ GroupedOptions options = GroupedOptions.select(params,
+ new Options(new Uncertainty()),
+ new Options(new Count()));
+ if (options == null)
+ {
+ printHelp();
+ System.out.println("Invalid USER options provided, see output for valid options");
+ System.exit(1);
+ }
+ return new SettingsCommandUser((Options) options);
+ }
+
+ public static void printHelp()
+ {
+ GroupedOptions.printOptions(System.out, "user",
+ new Options(new Uncertainty()),
+ new Options(new Count()));
+ }
+
+ public static Runnable helpPrinter()
+ {
+ return new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ printHelp();
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java
index ab489be..017b106 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java
@@ -26,23 +26,25 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import org.apache.cassandra.stress.generatedata.DataGenHexFromDistribution;
-import org.apache.cassandra.stress.generatedata.DataGenHexFromOpIndex;
-import org.apache.cassandra.stress.generatedata.DistributionFactory;
-import org.apache.cassandra.stress.generatedata.KeyGen;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.SeedGenerator;
+import org.apache.cassandra.stress.generate.SeedRandomGenerator;
+import org.apache.cassandra.stress.generate.SeedSeriesGenerator;
// Settings for key generation
public class SettingsKey implements Serializable
{
- private final int keySize;
+ final int keySize;
private final DistributionFactory distribution;
+ private final DistributionFactory clustering;
private final long[] range;
public SettingsKey(DistributionOptions options)
{
this.keySize = Integer.parseInt(options.size.value());
this.distribution = options.dist.get();
+ this.clustering = options.clustering.get();
this.range = null;
}
@@ -50,8 +52,9 @@ public class SettingsKey implements Serializable
{
this.keySize = Integer.parseInt(options.size.value());
this.distribution = null;
+ this.clustering = null;
String[] bounds = options.populate.value().split("\\.\\.+");
- this.range = new long[] { Long.parseLong(bounds[0]), Long.parseLong(bounds[1]) };
+ this.range = new long[] { OptionDistribution.parseLong(bounds[0]), OptionDistribution.parseLong(bounds[1]) };
}
// Option Declarations
@@ -59,6 +62,7 @@ public class SettingsKey implements Serializable
private static final class DistributionOptions extends GroupedOptions
{
final OptionDistribution dist;
+ final OptionDistribution clustering = new OptionDistribution("cluster=", "fixed(1)", "Keys are clustered in adjacent value runs of this size");
final OptionSimple size = new OptionSimple("size=", "[0-9]+", "10", "Key size in bytes", false);
public DistributionOptions(String defaultLimit)
@@ -69,7 +73,7 @@ public class SettingsKey implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(dist, size);
+ return Arrays.asList(dist, size, clustering);
}
}
@@ -80,7 +84,7 @@ public class SettingsKey implements Serializable
public PopulateOptions(String defaultLimit)
{
- populate = new OptionSimple("populate=", "[0-9]+\\.\\.+[0-9]+",
+ populate = new OptionSimple("populate=", "[0-9]+\\.\\.+[0-9]+[MBK]?",
"1.." + defaultLimit,
"Populate all keys in sequence", true);
}
@@ -92,12 +96,9 @@ public class SettingsKey implements Serializable
}
}
- public KeyGen newKeyGen()
+ public SeedGenerator newSeedGenerator()
{
- return new KeyGen(range == null
- ? new DataGenHexFromDistribution(distribution.get())
- : new DataGenHexFromOpIndex(range[0], range[1]),
- keySize);
+ return range == null ? new SeedRandomGenerator(distribution.get(), clustering.get()) : new SeedSeriesGenerator(range[0], range[1]);
}
// CLI Utility Methods
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java
index 8a5975f..5735f9d 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java
@@ -27,7 +27,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import org.apache.cassandra.stress.generatedata.Distribution;
+import org.apache.cassandra.stress.generate.Distribution;
public class SettingsMisc implements Serializable
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
index 95c3da3..1aa745c 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
@@ -161,8 +161,10 @@ public class SettingsMode implements Serializable
String[] params = clArgs.remove("-mode");
if (params == null)
{
- ThriftOptions opts = new ThriftOptions();
- opts.smart.accept("smart");
+ Cql3NativeOptions opts = new Cql3NativeOptions();
+ opts.accept("cql3");
+ opts.accept("native");
+ opts.accept("prepared");
return new SettingsMode(opts);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
index ffafb67..5fb2bb2 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
@@ -25,40 +25,51 @@ import java.nio.ByteBuffer;
import java.util.*;
import org.apache.cassandra.thrift.*;
+import org.apache.cassandra.thrift.ConsistencyLevel;
import org.apache.cassandra.utils.ByteBufferUtil;
public class SettingsSchema implements Serializable
{
- public static final String DEFAULT_COMPARATOR = "AsciiType";
public static final String DEFAULT_VALIDATOR = "BytesType";
private final String replicationStrategy;
private final Map<String, String> replicationStrategyOptions;
- private final IndexType indexType;
private final String compression;
private final String compactionStrategy;
private final Map<String, String> compactionStrategyOptions;
public final String keyspace;
- public SettingsSchema(Options options)
+ public SettingsSchema(Options options, SettingsCommand command)
{
+ if (command instanceof SettingsCommandUser)
+ {
+ if (options.compaction.setByUser() || options.keyspace.setByUser() || options.compression.setByUser() || options.replication.setByUser())
+ throw new IllegalArgumentException("Cannot provide command line schema settings if a user profile is provided");
+
+ keyspace = ((SettingsCommandUser) command).profile.keyspaceName;
+ }
+ else
+ keyspace = options.keyspace.value();
+
replicationStrategy = options.replication.getStrategy();
replicationStrategyOptions = options.replication.getOptions();
- if (options.index.setByUser())
- indexType = IndexType.valueOf(options.index.value().toUpperCase());
- else
- indexType = null;
compression = options.compression.value();
compactionStrategy = options.compaction.getStrategy();
compactionStrategyOptions = options.compaction.getOptions();
- keyspace = options.keyspace.value();
}
public void createKeySpaces(StressSettings settings)
{
- createKeySpacesThrift(settings);
+ if (!(settings.command instanceof SettingsCommandUser))
+ {
+ createKeySpacesThrift(settings);
+ }
+ else
+ {
+ ((SettingsCommandUser) settings.command).profile.maybeCreateSchema(settings);
+ }
}
@@ -71,7 +82,7 @@ public class SettingsSchema implements Serializable
// column family for standard columns
CfDef standardCfDef = new CfDef(keyspace, "Standard1");
- Map<String, String> compressionOptions = new HashMap<String, String>();
+ Map<String, String> compressionOptions = new HashMap<>();
if (compression != null)
compressionOptions.put("sstable_compression", compression);
@@ -80,28 +91,8 @@ public class SettingsSchema implements Serializable
.setDefault_validation_class(DEFAULT_VALIDATOR)
.setCompression_options(compressionOptions);
- if (!settings.columns.useTimeUUIDComparator)
- {
- for (int i = 0; i < settings.columns.maxColumnsPerKey; i++)
- {
- standardCfDef.addToColumn_metadata(new ColumnDef(ByteBufferUtil.bytes("C" + i), "BytesType"));
- }
- }
-
- if (indexType != null)
- {
- ColumnDef standardColumn = new ColumnDef(ByteBufferUtil.bytes("C1"), "BytesType");
- standardColumn.setIndex_type(indexType).setIndex_name("Idx1");
- standardCfDef.setColumn_metadata(Arrays.asList(standardColumn));
- }
-
- // column family with super columns
- CfDef superCfDef = new CfDef(keyspace, "Super1")
- .setColumn_type("Super");
- superCfDef.setComparator_type(DEFAULT_COMPARATOR)
- .setSubcomparator_type(comparator)
- .setDefault_validation_class(DEFAULT_VALIDATOR)
- .setCompression_options(compressionOptions);
+ for (int i = 0; i < settings.columns.names.size(); i++)
+ standardCfDef.addToColumn_metadata(new ColumnDef(settings.columns.names.get(i), "BytesType"));
// column family for standard counters
CfDef counterCfDef = new CfDef(keyspace, "Counter1")
@@ -109,13 +100,6 @@ public class SettingsSchema implements Serializable
.setDefault_validation_class("CounterColumnType")
.setCompression_options(compressionOptions);
- // column family with counter super columns
- CfDef counterSuperCfDef = new CfDef(keyspace, "SuperCounter1")
- .setComparator_type(comparator)
- .setDefault_validation_class("CounterColumnType")
- .setColumn_type("Super")
- .setCompression_options(compressionOptions);
-
ksdef.setName(keyspace);
ksdef.setStrategy_class(replicationStrategy);
@@ -127,19 +111,15 @@ public class SettingsSchema implements Serializable
if (compactionStrategy != null)
{
standardCfDef.setCompaction_strategy(compactionStrategy);
- superCfDef.setCompaction_strategy(compactionStrategy);
counterCfDef.setCompaction_strategy(compactionStrategy);
- counterSuperCfDef.setCompaction_strategy(compactionStrategy);
if (!compactionStrategyOptions.isEmpty())
{
standardCfDef.setCompaction_strategy_options(compactionStrategyOptions);
- superCfDef.setCompaction_strategy_options(compactionStrategyOptions);
counterCfDef.setCompaction_strategy_options(compactionStrategyOptions);
- counterSuperCfDef.setCompaction_strategy_options(compactionStrategyOptions);
}
}
- ksdef.setCf_defs(new ArrayList<>(Arrays.asList(standardCfDef, superCfDef, counterCfDef, counterSuperCfDef)));
+ ksdef.setCf_defs(new ArrayList<>(Arrays.asList(standardCfDef, counterCfDef)));
Cassandra.Client client = settings.getRawThriftClient(false);
@@ -191,24 +171,23 @@ public class SettingsSchema implements Serializable
{
final OptionReplication replication = new OptionReplication();
final OptionCompaction compaction = new OptionCompaction();
- final OptionSimple index = new OptionSimple("index=", "KEYS|CUSTOM|COMPOSITES", null, "Type of index to create on needed column families (KEYS)", false);
final OptionSimple keyspace = new OptionSimple("keyspace=", ".*", "Keyspace1", "The keyspace name to use", false);
final OptionSimple compression = new OptionSimple("compression=", ".*", null, "Specify the compression to use for sstable, default:no compression", false);
@Override
public List<? extends Option> options()
{
- return Arrays.asList(replication, index, keyspace, compaction, compression);
+ return Arrays.asList(replication, keyspace, compaction, compression);
}
}
// CLI Utility Methods
- public static SettingsSchema get(Map<String, String[]> clArgs)
+ public static SettingsSchema get(Map<String, String[]> clArgs, SettingsCommand command)
{
String[] params = clArgs.remove("-schema");
if (params == null)
- return new SettingsSchema(new Options());
+ return new SettingsSchema(new Options(), command);
GroupedOptions options = GroupedOptions.select(params, new Options());
if (options == null)
@@ -217,7 +196,7 @@ public class SettingsSchema implements Serializable
System.out.println("Invalid -schema options provided, see output for valid options");
System.exit(1);
}
- return new SettingsSchema((Options) options);
+ return new SettingsSchema((Options) options, command);
}
public static void printHelp()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
index 396095d..8b0ef6a 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
@@ -111,7 +111,7 @@ public class SettingsTransport implements Serializable
// Option Declarations
- static class TOptions extends GroupedOptions
+ static class TOptions extends GroupedOptions implements Serializable
{
final OptionSimple factory = new OptionSimple("factory=", ".*", TFramedTransportFactory.class.getName(), "Fully-qualified ITransportFactory class name for creating a connection. Note: For Thrift over SSL, use org.apache.cassandra.thrift.SSLTransportFactory.", false);
final OptionSimple trustStore = new OptionSimple("truststore=", ".*", null, "SSL: full path to truststore", false);
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
index a1d68b4..ab57289 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
@@ -29,6 +29,7 @@ import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.stress.util.JavaDriverClient;
import org.apache.cassandra.stress.util.SimpleThriftClient;
import org.apache.cassandra.stress.util.SmartThriftClient;
+import org.apache.cassandra.stress.util.ThriftClient;
import org.apache.cassandra.thrift.Cassandra;
import org.apache.cassandra.thrift.InvalidRequestException;
import org.apache.cassandra.transport.SimpleClient;
@@ -37,7 +38,6 @@ import org.apache.thrift.transport.TTransport;
public class StressSettings implements Serializable
{
-
public final SettingsCommand command;
public final SettingsRate rate;
public final SettingsKey keys;
@@ -65,7 +65,24 @@ public class StressSettings implements Serializable
this.sendToDaemon = sendToDaemon;
}
- public SmartThriftClient getSmartThriftClient()
+ private SmartThriftClient tclient;
+
+ /**
+ * Thrift client connection
+ * @return cassandra client connection
+ */
+ public synchronized ThriftClient getThriftClient()
+ {
+ if (mode.api != ConnectionAPI.THRIFT_SMART)
+ return getSimpleThriftClient();
+
+ if (tclient == null)
+ tclient = getSmartThriftClient();
+
+ return tclient;
+ }
+
+ private SmartThriftClient getSmartThriftClient()
{
Metadata metadata = getJavaDriverClient().getCluster().getMetadata();
return new SmartThriftClient(this, schema.keyspace, metadata);
@@ -75,7 +92,7 @@ public class StressSettings implements Serializable
* Thrift client connection
* @return cassandra client connection
*/
- public SimpleThriftClient getThriftClient()
+ private SimpleThriftClient getSimpleThriftClient()
{
return new SimpleThriftClient(getRawThriftClient(node.randomNode(), true));
}
@@ -139,6 +156,11 @@ public class StressSettings implements Serializable
public JavaDriverClient getJavaDriverClient()
{
+ return getJavaDriverClient(true);
+ }
+
+ public JavaDriverClient getJavaDriverClient(boolean setKeyspace)
+ {
if (client != null)
return client;
@@ -153,7 +175,9 @@ public class StressSettings implements Serializable
EncryptionOptions.ClientEncryptionOptions encOptions = transport.getEncryptionOptions();
JavaDriverClient c = new JavaDriverClient(currentNode, port.nativePort, encOptions);
c.connect(mode.compression());
- c.execute("USE \"" + schema.keyspace + "\";", org.apache.cassandra.db.ConsistencyLevel.ONE);
+ if (setKeyspace)
+ c.execute("USE \"" + schema.keyspace + "\";", org.apache.cassandra.db.ConsistencyLevel.ONE);
+
return client = c;
}
}
@@ -165,7 +189,7 @@ public class StressSettings implements Serializable
public void maybeCreateKeyspaces()
{
- if (command.type == Command.WRITE || command.type == Command.COUNTER_WRITE)
+ if (command.type == Command.WRITE || command.type == Command.COUNTER_WRITE || command.type == Command.USER)
schema.createKeySpaces(this);
}
@@ -202,7 +226,7 @@ public class StressSettings implements Serializable
SettingsLog log = SettingsLog.get(clArgs);
SettingsMode mode = SettingsMode.get(clArgs);
SettingsNode node = SettingsNode.get(clArgs);
- SettingsSchema schema = SettingsSchema.get(clArgs);
+ SettingsSchema schema = SettingsSchema.get(clArgs, command);
SettingsTransport transport = SettingsTransport.get(clArgs);
if (!clArgs.isEmpty())
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/ValidationType.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/ValidationType.java b/tools/stress/src/org/apache/cassandra/stress/settings/ValidationType.java
new file mode 100644
index 0000000..c22242d
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/ValidationType.java
@@ -0,0 +1,8 @@
+package org.apache.cassandra.stress.settings;
+
+public enum ValidationType
+{
+
+ NOT_FAIL, NON_ZERO, SUBSET, EQUAL
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java b/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java
index f216c05..c901461 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java
@@ -18,6 +18,8 @@
package org.apache.cassandra.stress.util;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import javax.net.ssl.SSLContext;
import com.datastax.driver.core.*;
@@ -40,6 +42,8 @@ public class JavaDriverClient
private Cluster cluster;
private Session session;
+ private static final ConcurrentMap<String, PreparedStatement> stmts = new ConcurrentHashMap<>();
+
public JavaDriverClient(String host, int port)
{
this(host, port, new EncryptionOptions.ClientEncryptionOptions());
@@ -54,7 +58,18 @@ public class JavaDriverClient
public PreparedStatement prepare(String query)
{
- return getSession().prepare(query);
+ PreparedStatement stmt = stmts.get(query);
+ if (stmt != null)
+ return stmt;
+ synchronized (stmts)
+ {
+ stmt = stmts.get(query);
+ if (stmt != null)
+ return stmt;
+ stmt = getSession().prepare(query);
+ stmts.put(query, stmt);
+ }
+ return stmt;
}
public void connect(ProtocolOptions.Compression compression) throws Exception
@@ -116,7 +131,7 @@ public class JavaDriverClient
* @param cl
* @return
*/
- ConsistencyLevel from(org.apache.cassandra.db.ConsistencyLevel cl)
+ public static ConsistencyLevel from(org.apache.cassandra.db.ConsistencyLevel cl)
{
switch (cl)
{
[20/23] git commit: Introduce CQL support for stress tool
Posted by be...@apache.org.
Introduce CQL support for stress tool
patch by Jake Luciani and Benedict Elliott Smith
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/75364296
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/75364296
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/75364296
Branch: refs/heads/cassandra-2.1.0
Commit: 75364296cb3749dfa6d4307cf055f1a18bcf7a9b
Parents: 61ee287
Author: Benedict Elliott Smith <be...@apache.org>
Authored: Mon Jul 7 18:03:59 2014 +0100
Committer: Benedict Elliott Smith <be...@apache.org>
Committed: Mon Jul 7 18:25:11 2014 +0100
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../cassandra/thrift/ThriftConversion.java | 19 +
.../org/apache/cassandra/utils/UUIDGen.java | 8 +
tools/bin/cassandra-stress | 2 +-
tools/cqlstress-counter-example.yaml | 85 +++
tools/cqlstress-example.yaml | 99 +++
tools/cqlstress-insanity-example.yaml | 102 +++
.../org/apache/cassandra/stress/Operation.java | 218 +-----
.../apache/cassandra/stress/StressAction.java | 262 +++----
.../apache/cassandra/stress/StressMetrics.java | 17 +-
.../apache/cassandra/stress/StressProfile.java | 504 +++++++++++++
.../org/apache/cassandra/stress/StressYaml.java | 38 +
.../cassandra/stress/generate/Distribution.java | 57 ++
.../generate/DistributionBoundApache.java | 84 +++
.../stress/generate/DistributionFactory.java | 31 +
.../stress/generate/DistributionFixed.java | 54 ++
.../stress/generate/DistributionInverted.java | 37 +
.../generate/DistributionOffsetApache.java | 80 +++
.../cassandra/stress/generate/Partition.java | 343 +++++++++
.../stress/generate/PartitionGenerator.java | 80 +++
.../stress/generate/RatioDistribution.java | 25 +
.../generate/RatioDistributionFactory.java | 31 +
.../apache/cassandra/stress/generate/Row.java | 22 +
.../stress/generate/SeedGenerator.java | 8 +
.../stress/generate/SeedRandomGenerator.java | 33 +
.../stress/generate/SeedSeriesGenerator.java | 21 +
.../stress/generate/values/Booleans.java | 37 +
.../cassandra/stress/generate/values/Bytes.java | 54 ++
.../cassandra/stress/generate/values/Dates.java | 46 ++
.../stress/generate/values/Doubles.java | 37 +
.../stress/generate/values/Floats.java | 37 +
.../stress/generate/values/Generator.java | 50 ++
.../stress/generate/values/GeneratorConfig.java | 68 ++
.../stress/generate/values/HexBytes.java | 56 ++
.../stress/generate/values/HexStrings.java | 55 ++
.../cassandra/stress/generate/values/Inets.java | 57 ++
.../stress/generate/values/Integers.java | 38 +
.../cassandra/stress/generate/values/Lists.java | 55 ++
.../cassandra/stress/generate/values/Longs.java | 37 +
.../cassandra/stress/generate/values/Sets.java | 54 ++
.../stress/generate/values/Strings.java | 49 ++
.../stress/generate/values/TimeUUIDs.java | 51 ++
.../cassandra/stress/generate/values/UUIDs.java | 39 +
.../cassandra/stress/generatedata/DataGen.java | 39 -
.../stress/generatedata/DataGenBytesRandom.java | 45 --
.../stress/generatedata/DataGenFactory.java | 30 -
.../stress/generatedata/DataGenHex.java | 60 --
.../DataGenHexFromDistribution.java | 66 --
.../generatedata/DataGenHexFromOpIndex.java | 48 --
.../generatedata/DataGenStringDictionary.java | 107 ---
.../generatedata/DataGenStringRepeats.java | 90 ---
.../stress/generatedata/Distribution.java | 40 --
.../generatedata/DistributionBoundApache.java | 63 --
.../generatedata/DistributionFactory.java | 31 -
.../stress/generatedata/DistributionFixed.java | 46 --
.../generatedata/DistributionOffsetApache.java | 61 --
.../generatedata/DistributionSeqBatch.java | 68 --
.../cassandra/stress/generatedata/KeyGen.java | 54 --
.../cassandra/stress/generatedata/RowGen.java | 53 --
.../generatedata/RowGenDistributedSize.java | 116 ---
.../stress/operations/CqlCounterAdder.java | 77 --
.../stress/operations/CqlCounterGetter.java | 69 --
.../operations/CqlIndexedRangeSlicer.java | 118 ---
.../stress/operations/CqlInserter.java | 88 ---
.../stress/operations/CqlMultiGetter.java | 42 --
.../stress/operations/CqlOperation.java | 698 ------------------
.../stress/operations/CqlRangeSlicer.java | 59 --
.../cassandra/stress/operations/CqlReader.java | 91 ---
.../stress/operations/FixedOpDistribution.java | 25 +
.../stress/operations/OpDistribution.java | 11 +
.../operations/OpDistributionFactory.java | 12 +
.../operations/SampledOpDistribution.java | 41 ++
.../SampledOpDistributionFactory.java | 72 ++
.../stress/operations/ThriftCounterAdder.java | 95 ---
.../stress/operations/ThriftCounterGetter.java | 68 --
.../operations/ThriftIndexedRangeSlicer.java | 114 ---
.../stress/operations/ThriftInserter.java | 117 ---
.../stress/operations/ThriftMultiGetter.java | 80 ---
.../stress/operations/ThriftRangeSlicer.java | 85 ---
.../stress/operations/ThriftReader.java | 94 ---
.../operations/predefined/CqlCounterAdder.java | 84 +++
.../operations/predefined/CqlCounterGetter.java | 74 ++
.../operations/predefined/CqlInserter.java | 79 ++
.../operations/predefined/CqlOperation.java | 714 +++++++++++++++++++
.../stress/operations/predefined/CqlReader.java | 87 +++
.../predefined/PredefinedOperation.java | 248 +++++++
.../predefined/ThriftCounterAdder.java | 86 +++
.../predefined/ThriftCounterGetter.java | 66 ++
.../operations/predefined/ThriftInserter.java | 96 +++
.../operations/predefined/ThriftReader.java | 79 ++
.../operations/userdefined/SchemaInsert.java | 144 ++++
.../operations/userdefined/SchemaQuery.java | 86 +++
.../operations/userdefined/SchemaStatement.java | 164 +++++
.../cassandra/stress/settings/Command.java | 24 +-
.../stress/settings/CommandCategory.java | 4 +-
.../stress/settings/OptionAnyProbabilities.java | 78 ++
.../stress/settings/OptionDataGen.java | 203 ------
.../stress/settings/OptionDistribution.java | 75 +-
.../settings/OptionEnumProbabilities.java | 62 ++
.../cassandra/stress/settings/OptionMulti.java | 3 +-
.../settings/OptionRatioDistribution.java | 166 +++++
.../cassandra/stress/settings/OptionSimple.java | 5 +-
.../stress/settings/SettingsColumn.java | 50 +-
.../stress/settings/SettingsCommand.java | 58 +-
.../stress/settings/SettingsCommandMixed.java | 207 ------
.../settings/SettingsCommandPreDefined.java | 145 ++++
.../SettingsCommandPreDefinedMixed.java | 151 ++++
.../stress/settings/SettingsCommandUser.java | 135 ++++
.../cassandra/stress/settings/SettingsKey.java | 27 +-
.../cassandra/stress/settings/SettingsMisc.java | 2 +-
.../cassandra/stress/settings/SettingsMode.java | 6 +-
.../stress/settings/SettingsSchema.java | 77 +-
.../stress/settings/SettingsTransport.java | 2 +-
.../stress/settings/StressSettings.java | 36 +-
.../stress/settings/ValidationType.java | 8 +
.../cassandra/stress/util/JavaDriverClient.java | 19 +-
.../stress/util/SmartThriftClient.java | 4 +-
.../org/apache/cassandra/stress/util/Timer.java | 17 +-
.../cassandra/stress/util/TimingInterval.java | 26 +-
119 files changed, 5861 insertions(+), 3890 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 491ad6d..ff2f586 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
2.1.0-rc3
+ * Introduce CQL support for stress tool (CASSANDRA-6146)
* Fix ClassCastException processing expired messages (CASSANDRA-7496)
* Fix prepared marker for collections inside UDT (CASSANDRA-7472)
* Remove left-over populate_io_cache_on_flush and replicate_on_write
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/src/java/org/apache/cassandra/thrift/ThriftConversion.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/thrift/ThriftConversion.java b/src/java/org/apache/cassandra/thrift/ThriftConversion.java
index 9573b56..0c75d2c 100644
--- a/src/java/org/apache/cassandra/thrift/ThriftConversion.java
+++ b/src/java/org/apache/cassandra/thrift/ThriftConversion.java
@@ -51,6 +51,25 @@ public class ThriftConversion
throw new AssertionError();
}
+ public static ConsistencyLevel toThrift(org.apache.cassandra.db.ConsistencyLevel cl)
+ {
+ switch (cl)
+ {
+ case ANY: return ConsistencyLevel.ANY;
+ case ONE: return ConsistencyLevel.ONE;
+ case TWO: return ConsistencyLevel.TWO;
+ case THREE: return ConsistencyLevel.THREE;
+ case QUORUM: return ConsistencyLevel.QUORUM;
+ case ALL: return ConsistencyLevel.ALL;
+ case LOCAL_QUORUM: return ConsistencyLevel.LOCAL_QUORUM;
+ case EACH_QUORUM: return ConsistencyLevel.EACH_QUORUM;
+ case SERIAL: return ConsistencyLevel.SERIAL;
+ case LOCAL_SERIAL: return ConsistencyLevel.LOCAL_SERIAL;
+ case LOCAL_ONE: return ConsistencyLevel.LOCAL_ONE;
+ }
+ throw new AssertionError();
+ }
+
// We never return, but returning a RuntimeException allows to write "throw rethrow(e)" without java complaining
// for methods that have a return value.
public static RuntimeException rethrow(RequestExecutionException e) throws UnavailableException, TimedOutException
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/src/java/org/apache/cassandra/utils/UUIDGen.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/utils/UUIDGen.java b/src/java/org/apache/cassandra/utils/UUIDGen.java
index f385744..53293b2 100644
--- a/src/java/org/apache/cassandra/utils/UUIDGen.java
+++ b/src/java/org/apache/cassandra/utils/UUIDGen.java
@@ -25,6 +25,8 @@ import java.util.Collection;
import java.util.Random;
import java.util.UUID;
+import com.google.common.annotations.VisibleForTesting;
+
/**
* The goods are here: www.ietf.org/rfc/rfc4122.txt.
@@ -80,6 +82,12 @@ public class UUIDGen
return new UUID(createTime(fromUnixTimestamp(when)), clockSeqAndNode);
}
+ @VisibleForTesting
+ public static UUID getTimeUUID(long when, long clockSeqAndNode)
+ {
+ return new UUID(createTime(fromUnixTimestamp(when)), clockSeqAndNode);
+ }
+
/** creates a type 1 uuid from raw bytes. */
public static UUID getUUID(ByteBuffer raw)
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/bin/cassandra-stress
----------------------------------------------------------------------
diff --git a/tools/bin/cassandra-stress b/tools/bin/cassandra-stress
index 39257cd..c855cf5 100755
--- a/tools/bin/cassandra-stress
+++ b/tools/bin/cassandra-stress
@@ -42,4 +42,4 @@ if [ "x$JAVA" = "x" ]; then
exit 1
fi
-$JAVA -server -cp $CLASSPATH org.apache.cassandra.stress.Stress $@
+$JAVA -server -ea -cp $CLASSPATH org.apache.cassandra.stress.Stress $@
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/cqlstress-counter-example.yaml
----------------------------------------------------------------------
diff --git a/tools/cqlstress-counter-example.yaml b/tools/cqlstress-counter-example.yaml
new file mode 100644
index 0000000..a65080a
--- /dev/null
+++ b/tools/cqlstress-counter-example.yaml
@@ -0,0 +1,85 @@
+#
+# This is an example YAML profile for cassandra-stress
+#
+# insert data
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1)
+#
+# read, using query simple1:
+# cassandra-stress profile=/home/jake/stress1.yaml ops(simple1=1)
+#
+# mixed workload (90/10)
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1,simple1=9)
+
+
+#
+# Keyspace info
+#
+keyspace: stresscql
+
+#
+# The CQL for creating a keyspace (optional if it already exists)
+#
+keyspace_definition: |
+ CREATE KEYSPACE stresscql WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
+
+#
+# Table info
+#
+table: counttest
+
+#
+# The CQL for creating a table you wish to stress (optional if it already exists)
+#
+table_definition: |
+ CREATE TABLE counttest (
+ name text PRIMARY KEY,
+ count counter
+ ) WITH comment='A table of many types to test wide rows'
+
+#
+# Optional meta information on the generated columns in the above table
+# The min and max only apply to text and blob types
+# The distribution field represents the total unique population
+# distribution of that column across rows. Supported types are
+#
+# EXP(min..max) An exponential distribution over the range [min..max]
+# EXTREME(min..max,shape) An extreme value (Weibull) distribution over the range [min..max]
+# GAUSSIAN(min..max,stdvrng) A gaussian/normal distribution, where mean=(min+max)/2, and stdev is (mean-min)/stdvrng
+# GAUSSIAN(min..max,mean,stdev) A gaussian/normal distribution, with explicitly defined mean and stdev
+# UNIFORM(min..max) A uniform distribution over the range [min, max]
+# FIXED(val) A fixed distribution, always returning the same value
+# Aliases: extr, gauss, normal, norm, weibull
+#
+# If preceded by ~, the distribution is inverted
+#
+# Defaults for all columns are size: uniform(1..256), identity: uniform(1..1024)
+#
+
+columnspec:
+ - name: name
+ clustering: uniform(1..100)
+ size: uniform(1..4)
+ - name: count
+ population: fixed(1)
+
+insert:
+ partitions: fixed(1) # number of unique partitions to update in a single operation
+ # if perbatch < 1, multiple batches will be used but all partitions will
+ # occur in all batches (unless already finished); only the row counts will vary
+ pervisit: fixed(1)/1 # ratio of rows each partition should update in a single visit to the partition,
+ # as a proportion of the total possible for the partition
+ perbatch: fixed(1)/1 # number of rows each partition should update in a single batch statement,
+ # as a proportion of the proportion we are inserting this visit
+ # (i.e. compounds with (and capped by) pervisit)
+ batchtype: UNLOGGED # type of batch to use
+
+#
+# A list of queries you wish to run against the schema
+#
+queries:
+ simple1: select * from counttest where name = ?
+
+#
+# In order to generate data consistently we need something to generate a unique key for this schema profile.
+#
+seed: changing this string changes the generated data. its hashcode is used as the random seed.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/cqlstress-example.yaml
----------------------------------------------------------------------
diff --git a/tools/cqlstress-example.yaml b/tools/cqlstress-example.yaml
new file mode 100644
index 0000000..a997529
--- /dev/null
+++ b/tools/cqlstress-example.yaml
@@ -0,0 +1,99 @@
+#
+# This is an example YAML profile for cassandra-stress
+#
+# insert data
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1)
+#
+# read, using query simple1:
+# cassandra-stress profile=/home/jake/stress1.yaml ops(simple1=1)
+#
+# mixed workload (90/10)
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1,simple1=9)
+
+
+#
+# Keyspace info
+#
+keyspace: stresscql
+
+#
+# The CQL for creating a keyspace (optional if it already exists)
+#
+keyspace_definition: |
+ CREATE KEYSPACE stresscql WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
+
+#
+# Table info
+#
+table: typestest
+
+#
+# The CQL for creating a table you wish to stress (optional if it already exists)
+#
+table_definition: |
+ CREATE TABLE typestest (
+ name text,
+ choice boolean,
+ date timestamp,
+ address inet,
+ dbl double,
+ lval bigint,
+ ival int,
+ uid timeuuid,
+ value blob,
+ PRIMARY KEY((name,choice), date, address, dbl, lval, ival, uid)
+ ) WITH COMPACT STORAGE
+ AND compaction = { 'class':'LeveledCompactionStrategy' }
+ AND comment='A table of many types to test wide rows'
+
+#
+# Optional meta information on the generated columns in the above table
+# The min and max only apply to text and blob types
+# The distribution field represents the total unique population
+# distribution of that column across rows. Supported types are
+#
+# EXP(min..max) An exponential distribution over the range [min..max]
+# EXTREME(min..max,shape) An extreme value (Weibull) distribution over the range [min..max]
+# GAUSSIAN(min..max,stdvrng) A gaussian/normal distribution, where mean=(min+max)/2, and stdev is (mean-min)/stdvrng
+# GAUSSIAN(min..max,mean,stdev) A gaussian/normal distribution, with explicitly defined mean and stdev
+# UNIFORM(min..max) A uniform distribution over the range [min, max]
+# FIXED(val) A fixed distribution, always returning the same value
+# Aliases: extr, gauss, normal, norm, weibull
+#
+# If preceded by ~, the distribution is inverted
+#
+# Defaults for all columns are size: uniform(1..256), identity: uniform(1..1024)
+#
+columnspec:
+ - name: name
+ size: uniform(1..10)
+ population: uniform(1..1M) # the range of unique values to select for the field (default is 100Billion)
+ - name: choice
+ - name: date
+ cluster: uniform(1..4)
+ - name: lval
+ population: gaussian(1..1000)
+ cluster: uniform(1..4)
+
+insert:
+ partitions: uniform(1..50) # number of unique partitions to update in a single operation
+ # if perbatch < 1, multiple batches will be used but all partitions will
+ # occur in all batches (unless already finished); only the row counts will vary
+ pervisit: uniform(1..10)/10 # ratio of rows each partition should update in a single visit to the partition,
+ # as a proportion of the total possible for the partition
+ perbatch: ~exp(1..3)/4 # number of rows each partition should update in a single batch statement,
+ # as a proportion of the proportion we are inserting this visit
+ # (i.e. compounds with (and capped by) pervisit)
+ batchtype: UNLOGGED # type of batch to use
+
+#
+# A list of queries you wish to run against the schema
+#
+queries:
+ simple1: select * from typestest where name = ? and choice = ? LIMIT 100
+ range1: select * from typestest where name = ? and choice = ? and date >= ? LIMIT 100
+
+#
+# In order to generate data consistently we need something to generate a unique key for this schema profile.
+#
+seed: changing this string changes the generated data. its hashcode is used as the random seed.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/cqlstress-insanity-example.yaml
----------------------------------------------------------------------
diff --git a/tools/cqlstress-insanity-example.yaml b/tools/cqlstress-insanity-example.yaml
new file mode 100644
index 0000000..e94c9c3
--- /dev/null
+++ b/tools/cqlstress-insanity-example.yaml
@@ -0,0 +1,102 @@
+#
+# This is an example YAML profile for cassandra-stress
+#
+# insert data
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1)
+#
+# read, using query simple1:
+# cassandra-stress profile=/home/jake/stress1.yaml ops(simple1=1)
+#
+# mixed workload (90/10)
+# cassandra-stress user profile=/home/jake/stress1.yaml ops(insert=1,simple1=9)
+
+
+#
+# Keyspace info
+#
+keyspace: stresscql
+
+#
+# The CQL for creating a keyspace (optional if it already exists)
+#
+keyspace_definition: |
+ CREATE KEYSPACE stresscql WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
+
+#
+# Table info
+#
+table: insanitytest
+
+#
+# The CQL for creating a table you wish to stress (optional if it already exists)
+#
+table_definition: |
+ CREATE TABLE insanitytest (
+ name text,
+ choice boolean,
+ date timestamp,
+ address inet,
+ dbl double,
+ lval bigint,
+ fval float,
+ ival int,
+ uid timeuuid,
+ dates list<timestamp>,
+ inets set<inet>,
+ value blob,
+ PRIMARY KEY((name, choice), date)
+ ) WITH compaction = { 'class':'LeveledCompactionStrategy' }
+ AND comment='A table of many types to test wide rows and collections'
+
+#
+# Optional meta information on the generated columns in the above table
+# The min and max only apply to text and blob types
+# The distribution field represents the total unique population
+# distribution of that column across rows. Supported types are
+#
+# EXP(min..max) An exponential distribution over the range [min..max]
+# EXTREME(min..max,shape) An extreme value (Weibull) distribution over the range [min..max]
+# GAUSSIAN(min..max,stdvrng) A gaussian/normal distribution, where mean=(min+max)/2, and stdev is (mean-min)/stdvrng
+# GAUSSIAN(min..max,mean,stdev) A gaussian/normal distribution, with explicitly defined mean and stdev
+# UNIFORM(min..max) A uniform distribution over the range [min, max]
+# FIXED(val) A fixed distribution, always returning the same value
+# Aliases: extr, gauss, normal, norm, weibull
+#
+# If preceded by ~, the distribution is inverted
+#
+# Defaults for all columns are size: uniform(1..256), population: uniform(1..100B)
+#
+columnspec:
+ - name: name
+ clustering: uniform(1..4)
+ - name: date
+ clustering: gaussian(1..20)
+ - name: lval
+ population: fixed(1)
+ - name: dates
+ clustering: uniform(1..100)
+ - name: inets
+ clustering: uniform(1..200)
+ - name: value
+
+insert:
+ partitions: fixed(1) # number of unique partitions to update in a single operation
+ # if perbatch < 1, multiple batches will be used but all partitions will
+ # occur in all batches (unless already finished); only the row counts will vary
+ pervisit: uniform(1..10)/100K # ratio of rows each partition should update in a single visit to the partition,
+ # as a proportion of the total possible for the partition
+ perbatch: fixed(1)/1 # number of rows each partition should update in a single batch statement,
+ # as a proportion of the proportion we are inserting this visit
+ # (i.e. compounds with (and capped by) pervisit)
+ batchtype: UNLOGGED # type of batch to use
+
+#
+# A list of queries you wish to run against the schema
+#
+queries:
+ simple1: select * from insanitytest where name = ? and choice = ? LIMIT 100
+
+#
+# In order to generate data consistently we need something to generate a unique key for this schema profile.
+#
+seed: changing this string changes the generated data. its hashcode is used as the random seed.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/Operation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/Operation.java b/tools/stress/src/org/apache/cassandra/stress/Operation.java
index 87afb3d..7831074 100644
--- a/tools/stress/src/org/apache/cassandra/stress/Operation.java
+++ b/tools/stress/src/org/apache/cassandra/stress/Operation.java
@@ -18,203 +18,47 @@
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.generate.Distribution;
+import org.apache.cassandra.stress.generate.Partition;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
import org.apache.cassandra.stress.settings.*;
import org.apache.cassandra.stress.util.JavaDriverClient;
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;
public abstract class Operation
{
- public final long index;
- protected final State state;
+ public final StressSettings settings;
+ public final Timer timer;
+ public final PartitionGenerator generator;
+ public final Distribution partitionCount;
- public Operation(State state, long idx)
+ protected List<Partition> partitions;
+
+ public Operation(Timer timer, PartitionGenerator generator, StressSettings settings, Distribution partitionCount)
{
- index = idx;
- this.state = state;
+ this.generator = generator;
+ this.timer = timer;
+ this.settings = settings;
+ this.partitionCount = partitionCount;
}
public static interface RunOp
{
public boolean run() throws Exception;
- public String key();
- public int keyCount();
+ public int partitionCount();
+ public int rowCount();
}
- // one per thread!
- public static final class State
+ protected void setPartitions(List<Partition> partitions)
{
-
- public final StressSettings settings;
- public final Timer timer;
- public final Command type;
- public final KeyGen keyGen;
- public final RowGen rowGen;
- public final Distribution counteradd;
- public final List<ColumnParent> columnParents;
- public final StressMetrics metrics;
- public final SettingsCommandMixed.CommandSelector commandSelector;
- private final EnumMap<Command, State> substates;
- private Object cqlCache;
-
- public State(Command type, StressSettings settings, StressMetrics metrics)
- {
- this.type = type;
- this.timer = metrics.getTiming().newTimer();
- if (type == Command.MIXED)
- {
- commandSelector = ((SettingsCommandMixed) settings.command).selector();
- substates = new EnumMap<>(Command.class);
- }
- else
- {
- 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;
- this.columnParents = columnParents(type, settings);
- }
-
- private State(Command type, State copy)
- {
- this.type = type;
- this.timer = copy.timer;
- this.rowGen = copy.rowGen;
- this.keyGen = copy.keyGen;
- 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<ColumnParent> 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;
- }
- public boolean isCql2()
- {
- return settings.mode.cqlVersion == CqlVersion.CQL2;
- }
- public Object getCqlCache()
- {
- return cqlCache;
- }
- public void storeCqlCache(Object val)
- {
- cqlCache = val;
- }
-
- public State substate(Command command)
- {
- assert type == Command.MIXED;
- State substate = substates.get(command);
- if (substate == null)
- {
- substates.put(command, substate = new State(command, this));
- }
- return substate;
- }
-
- }
-
- protected ByteBuffer getKey()
- {
- return state.keyGen.getKeys(1, index).get(0);
- }
-
- protected List<ByteBuffer> getKeys(int count)
- {
- return state.keyGen.getKeys(count, index);
- }
-
- protected List<ByteBuffer> generateColumnValues(ByteBuffer key)
- {
- 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<ByteBuffer> randomNames()
- {
- int count = state.rowGen.count(index);
- List<ByteBuffer> src = state.settings.columns.names;
- if (count == src.size())
- return src;
- ThreadLocalRandom rnd = ThreadLocalRandom.current();
- List<ByteBuffer> 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;
+ this.partitions = partitions;
}
/**
@@ -234,13 +78,13 @@ public abstract class Operation
public void timeWithRetry(RunOp run) throws IOException
{
- state.timer.start();
+ timer.start();
boolean success = false;
String exceptionMessage = null;
int tries = 0;
- for (; tries < state.settings.command.tries; tries++)
+ for (; tries < settings.command.tries; tries++)
{
try
{
@@ -249,7 +93,7 @@ public abstract class Operation
}
catch (Exception e)
{
- switch (state.settings.log.level)
+ switch (settings.log.level)
{
case MINIMAL:
break;
@@ -269,15 +113,13 @@ public abstract class Operation
}
}
- state.timer.stop(run.keyCount());
+ timer.stop(run.partitionCount(), run.rowCount());
if (!success)
{
- error(String.format("Operation [%d] x%d key %s (0x%s) %s%n",
- index,
+ error(String.format("Operation x%d on key(s) %s: %s%n",
tries,
- run.key(),
- ByteBufferUtil.bytesToHex(ByteBufferUtil.bytes(run.key())),
+ key(),
(exceptionMessage == null)
? "Data returned was not validated"
: "Error executing: " + exceptionMessage));
@@ -285,6 +127,14 @@ public abstract class Operation
}
+ private String key()
+ {
+ List<String> keys = new ArrayList<>();
+ for (Partition partition : partitions)
+ keys.add(partition.getKeyAsString());
+ return keys.toString();
+ }
+
protected String getExceptionMessage(Exception e)
{
String className = e.getClass().getSimpleName();
@@ -294,9 +144,9 @@ public abstract class Operation
protected void error(String message) throws IOException
{
- if (!state.settings.command.ignoreErrors)
+ if (!settings.command.ignoreErrors)
throw new IOException(message);
- else if (state.settings.log.level.compareTo(SettingsLog.Level.MINIMAL) > 0)
+ else if (settings.log.level.compareTo(SettingsLog.Level.MINIMAL) > 0)
System.err.println(message);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/StressAction.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressAction.java b/tools/stress/src/org/apache/cassandra/stress/StressAction.java
index 07ba1d8..2105a72 100644
--- a/tools/stress/src/org/apache/cassandra/stress/StressAction.java
+++ b/tools/stress/src/org/apache/cassandra/stress/StressAction.java
@@ -21,6 +21,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
@@ -29,10 +30,15 @@ import java.util.concurrent.atomic.AtomicLong;
import com.google.common.util.concurrent.RateLimiter;
import com.google.common.util.concurrent.Uninterruptibles;
-import org.apache.cassandra.stress.operations.*;
+
+import org.apache.cassandra.stress.generate.Partition;
+import org.apache.cassandra.stress.generate.SeedGenerator;
+import org.apache.cassandra.stress.operations.OpDistribution;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
import org.apache.cassandra.stress.settings.*;
import org.apache.cassandra.stress.util.JavaDriverClient;
import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
import org.apache.cassandra.transport.SimpleClient;
public class StressAction implements Runnable
@@ -52,7 +58,8 @@ public class StressAction implements Runnable
// creating keyspace and column families
settings.maybeCreateKeyspaces();
- warmup(settings.command.type, settings.command);
+ if (!settings.command.noWarmup)
+ warmup(settings.command.getFactory(settings));
output.println("Sleeping 2s...");
Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
@@ -61,7 +68,7 @@ public class StressAction implements Runnable
if (settings.rate.auto)
success = runAuto();
else
- success = null != run(settings.command.type, settings.rate.threadCount, settings.command.count, output);
+ success = null != run(settings.command.getFactory(settings), settings.rate.threadCount, settings.command.count, output);
if (success)
output.println("END");
@@ -72,33 +79,18 @@ public class StressAction implements Runnable
}
// type provided separately to support recursive call for mixed command with each command type it is performing
- private void warmup(Command type, SettingsCommand command)
+ private void warmup(OpDistributionFactory operations)
{
// warmup - do 50k iterations; by default hotspot compiles methods after 10k invocations
PrintStream warmupOutput = new PrintStream(new OutputStream() { @Override public void write(int b) throws IOException { } } );
- int iterations;
- switch (type.category)
+ int iterations = 50000 * settings.node.nodes.size();
+ for (OpDistributionFactory single : operations.each())
{
- case BASIC:
- iterations = 50000;
- break;
- case MIXED:
- for (Command subtype : ((SettingsCommandMixed) command).getCommands())
- warmup(subtype, command);
- return;
- case MULTI:
- int keysAtOnce = command.keysAtOnce;
- iterations = Math.min(50000, (int) Math.ceil(500000d / keysAtOnce));
- break;
- default:
- throw new IllegalStateException();
+ // we need to warm up all the nodes in the cluster ideally, but we may not be the only stress instance;
+ // so warm up all the nodes we're speaking to only.
+ output.println(String.format("Warming up %s with %d iterations...", single.desc(), iterations));
+ run(single, 20, iterations, warmupOutput);
}
-
- // we need to warm up all the nodes in the cluster ideally, but we may not be the only stress instance;
- // so warm up all the nodes we're speaking to only.
- iterations *= settings.node.nodes.size();
- output.println(String.format("Warming up %s with %d iterations...", type, iterations));
- run(type, 20, iterations, warmupOutput);
}
// TODO : permit varying more than just thread count
@@ -113,7 +105,7 @@ public class StressAction implements Runnable
{
output.println(String.format("Running with %d threadCount", threadCount));
- StressMetrics result = run(settings.command.type, threadCount, settings.command.count, output);
+ StressMetrics result = run(settings.command.getFactory(settings), threadCount, settings.command.count, output);
if (result == null)
return false;
results.add(result);
@@ -170,13 +162,13 @@ public class StressAction implements Runnable
return improvement / count;
}
- private StressMetrics run(Command type, int threadCount, long opCount, PrintStream output)
+ private StressMetrics run(OpDistributionFactory operations, int threadCount, long opCount, PrintStream output)
{
output.println(String.format("Running %s with %d threads %s",
- type.toString(),
- threadCount,
- opCount > 0 ? " for " + opCount + " iterations" : "until stderr of mean < " + settings.command.targetUncertainty));
+ operations.desc(),
+ threadCount,
+ opCount > 0 ? " for " + opCount + " iterations" : "until stderr of mean < " + settings.command.targetUncertainty));
final WorkQueue workQueue;
if (opCount < 0)
workQueue = new ContinuousWorkQueue(50);
@@ -193,7 +185,7 @@ public class StressAction implements Runnable
final CountDownLatch done = new CountDownLatch(threadCount);
final Consumer[] consumers = new Consumer[threadCount];
for (int i = 0; i < threadCount; i++)
- consumers[i] = new Consumer(type, done, workQueue, metrics, rateLimiter);
+ consumers[i] = new Consumer(operations, done, workQueue, metrics, rateLimiter);
// starting worker threadCount
for (int i = 0; i < threadCount; i++)
@@ -236,18 +228,24 @@ public class StressAction implements Runnable
private class Consumer extends Thread
{
- private final Operation.State state;
+ private final OpDistribution operations;
+ private final StressMetrics metrics;
+ private final Timer timer;
+ private final SeedGenerator seedGenerator;
private final RateLimiter rateLimiter;
private volatile boolean success = true;
private final WorkQueue workQueue;
private final CountDownLatch done;
- public Consumer(Command type, CountDownLatch done, WorkQueue workQueue, StressMetrics metrics, RateLimiter rateLimiter)
+ public Consumer(OpDistributionFactory operations, CountDownLatch done, WorkQueue workQueue, StressMetrics metrics, RateLimiter rateLimiter)
{
this.done = done;
this.rateLimiter = rateLimiter;
this.workQueue = workQueue;
- this.state = new Operation.State(type, settings, metrics);
+ this.metrics = metrics;
+ this.timer = metrics.getTiming().newTimer();
+ this.seedGenerator = settings.keys.newSeedGenerator();
+ this.operations = operations.get(timer);
}
public void run()
@@ -269,63 +267,89 @@ public class StressAction implements Runnable
sclient = settings.getSimpleNativeClient();
break;
case THRIFT:
- tclient = settings.getThriftClient();
- break;
case THRIFT_SMART:
- tclient = settings.getSmartThriftClient();
+ tclient = settings.getThriftClient();
break;
default:
throw new IllegalStateException();
}
- Work work;
- while ( null != (work = workQueue.poll()) )
+ int maxBatchSize = operations.maxBatchSize();
+ Work work = workQueue.poll();
+ Partition[] partitions = new Partition[maxBatchSize];
+ int workDone = 0;
+ while (work != null)
{
- if (rateLimiter != null)
- rateLimiter.acquire(work.count);
+ Operation op = operations.next();
+ op.generator.reset();
+ int batchSize = Math.max(1, (int) op.partitionCount.next());
+ int partitionCount = 0;
- for (int i = 0 ; i < work.count ; i++)
+ while (partitionCount < batchSize)
{
- try
+ int count = Math.min((work.count - workDone), batchSize - partitionCount);
+ for (int i = 0 ; i < count ; i++)
{
- Operation op = createOperation(state, i + work.offset);
- switch (settings.mode.api)
- {
- case JAVA_DRIVER_NATIVE:
- op.run(jclient);
- break;
- case SIMPLE_NATIVE:
- op.run(sclient);
- break;
- case THRIFT:
- case THRIFT_SMART:
- default:
- op.run(tclient);
- }
- } catch (Exception e)
+ long seed = seedGenerator.next(work.offset + workDone + i);
+ partitions[partitionCount + i] = op.generator.generate(seed);
+ }
+ workDone += count;
+ partitionCount += count;
+ if (workDone == work.count)
{
- if (output == null)
+ workDone = 0;
+ work = workQueue.poll();
+ if (work == null)
{
- System.err.println(e.getMessage());
- success = false;
- System.exit(-1);
+ if (partitionCount == 0)
+ return;
+ break;
}
+ if (rateLimiter != null)
+ rateLimiter.acquire(work.count);
+ }
+ }
+
+ op.setPartitions(Arrays.asList(partitions).subList(0, partitionCount));
- e.printStackTrace(output);
+ try
+ {
+ switch (settings.mode.api)
+ {
+ case JAVA_DRIVER_NATIVE:
+ op.run(jclient);
+ break;
+ case SIMPLE_NATIVE:
+ op.run(sclient);
+ break;
+ case THRIFT:
+ case THRIFT_SMART:
+ default:
+ op.run(tclient);
+ }
+ }
+ catch (Exception e)
+ {
+ if (output == null)
+ {
+ System.err.println(e.getMessage());
success = false;
- workQueue.stop();
- state.metrics.cancel();
- return;
+ System.exit(-1);
}
+
+ e.printStackTrace(output);
+ success = false;
+ workQueue.stop();
+ metrics.cancel();
+ return;
}
}
-
}
finally
{
done.countDown();
- state.timer.close();
+ timer.close();
}
}
@@ -443,106 +467,4 @@ public class StressAction implements Runnable
}
- private Operation createOperation(Operation.State state, long index)
- {
- return createOperation(state.type, state, index);
- }
- private Operation createOperation(Command type, Operation.State state, long index)
- {
- switch (type)
- {
- case READ:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftReader(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlReader(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
-
- case COUNTER_READ:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftCounterGetter(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlCounterGetter(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case WRITE:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftInserter(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlInserter(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case COUNTER_WRITE:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftCounterAdder(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlCounterAdder(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case RANGE_SLICE:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftRangeSlicer(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlRangeSlicer(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case INDEXED_RANGE_SLICE:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftIndexedRangeSlicer(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlIndexedRangeSlicer(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case READ_MULTI:
- switch(state.settings.mode.style)
- {
- case THRIFT:
- return new ThriftMultiGetter(state, index);
- case CQL:
- case CQL_PREPARED:
- return new CqlMultiGetter(state, index);
- default:
- throw new UnsupportedOperationException();
- }
-
- case MIXED:
- Command subcommand = state.commandSelector.next();
- return createOperation(subcommand, state.substate(subcommand), index);
-
- }
-
- throw new UnsupportedOperationException();
- }
-
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java b/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
index 54a1e2c..7e5c1b6 100644
--- a/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
+++ b/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
@@ -127,20 +127,21 @@ public class StressMetrics
// PRINT FORMATTING
- public static final String HEADFORMAT = "%-10s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%7s,%9s";
- public static final String ROWFORMAT = "%-10d,%8.0f,%8.0f,%8.1f,%8.1f,%8.1f,%8.1f,%8.1f,%8.1f,%7.1f,%9.5f";
+ public static final String HEADFORMAT = "%-10s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%7s,%9s";
+ public static final String ROWFORMAT = "%-10d,%8.0f,%8.0f,%8.0f,%8.1f,%8.1f,%8.1f,%8.1f,%8.1f,%8.1f,%7.1f,%9.5f";
private static void printHeader(String prefix, PrintStream output)
{
- output.println(prefix + String.format(HEADFORMAT, "ops","op/s", "key/s","mean","med",".95",".99",".999","max","time","stderr"));
+ output.println(prefix + String.format(HEADFORMAT, "partitions","op/s", "pk/s", "row/s","mean","med",".95",".99",".999","max","time","stderr"));
}
private static void printRow(String prefix, TimingInterval interval, TimingInterval total, Uncertainty opRateUncertainty, PrintStream output)
{
output.println(prefix + String.format(ROWFORMAT,
- total.operationCount,
+ total.partitionCount,
interval.realOpRate(),
- interval.keyRate(),
+ interval.partitionRate(),
+ interval.rowRate(),
interval.meanLatency(),
interval.medianLatency(),
interval.rankLatency(0.95f),
@@ -156,9 +157,9 @@ public class StressMetrics
output.println("\n");
output.println("Results:");
TimingInterval history = timing.getHistory();
- output.println(String.format("real op rate : %.0f", history.realOpRate()));
- output.println(String.format("adjusted op rate stderr : %.0f", opRateUncertainty.getUncertainty()));
- output.println(String.format("key rate : %.0f", history.keyRate()));
+ output.println(String.format("op rate : %.0f", history.realOpRate()));
+ output.println(String.format("partition rate : %.0f", history.partitionRate()));
+ output.println(String.format("row rate : %.0f", history.rowRate()));
output.println(String.format("latency mean : %.1f", history.meanLatency()));
output.println(String.format("latency median : %.1f", history.medianLatency()));
output.println(String.format("latency 95th percentile : %.1f", history.rankLatency(.95f)));
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressProfile.java b/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
new file mode 100644
index 0000000..13f26a2
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/StressProfile.java
@@ -0,0 +1,504 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress;
+
+
+import com.datastax.driver.core.*;
+import com.datastax.driver.core.exceptions.AlreadyExistsException;
+
+import com.google.common.util.concurrent.Uninterruptibles;
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.cql3.QueryProcessor;
+import org.apache.cassandra.cql3.statements.CreateKeyspaceStatement;
+import org.apache.cassandra.exceptions.RequestValidationException;
+
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.RatioDistributionFactory;
+import org.apache.cassandra.stress.generate.values.Booleans;
+import org.apache.cassandra.stress.generate.values.Bytes;
+import org.apache.cassandra.stress.generate.values.Generator;
+import org.apache.cassandra.stress.generate.values.Dates;
+import org.apache.cassandra.stress.generate.values.Doubles;
+import org.apache.cassandra.stress.generate.values.Floats;
+import org.apache.cassandra.stress.generate.values.GeneratorConfig;
+import org.apache.cassandra.stress.generate.values.Inets;
+import org.apache.cassandra.stress.generate.values.Integers;
+import org.apache.cassandra.stress.generate.values.Lists;
+import org.apache.cassandra.stress.generate.values.Longs;
+import org.apache.cassandra.stress.generate.values.Sets;
+import org.apache.cassandra.stress.generate.values.Strings;
+import org.apache.cassandra.stress.generate.values.TimeUUIDs;
+import org.apache.cassandra.stress.generate.values.UUIDs;
+import org.apache.cassandra.stress.operations.userdefined.SchemaInsert;
+import org.apache.cassandra.stress.operations.userdefined.SchemaQuery;
+import org.apache.cassandra.stress.settings.OptionDistribution;
+import org.apache.cassandra.stress.settings.OptionRatioDistribution;
+import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.settings.ValidationType;
+import org.apache.cassandra.stress.util.JavaDriverClient;
+import org.apache.cassandra.stress.util.ThriftClient;
+import org.apache.cassandra.stress.util.Timer;
+import org.apache.cassandra.thrift.Compression;
+import org.apache.cassandra.thrift.ThriftConversion;
+import org.apache.thrift.TException;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.error.YAMLException;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.Serializable;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+public class StressProfile implements Serializable
+{
+ private String keyspaceCql;
+ private String tableCql;
+ private String seedStr;
+
+ public String keyspaceName;
+ public String tableName;
+ private Map<String, GeneratorConfig> columnConfigs;
+ private Map<String, String> queries;
+ private Map<String, String> insert;
+
+ transient volatile TableMetadata tableMetaData;
+
+ transient volatile GeneratorFactory generatorFactory;
+
+ transient volatile BatchStatement.Type batchType;
+ transient volatile DistributionFactory partitions;
+ transient volatile RatioDistributionFactory pervisit;
+ transient volatile RatioDistributionFactory perbatch;
+ transient volatile PreparedStatement insertStatement;
+ transient volatile Integer thriftInsertId;
+
+ transient volatile Map<String, PreparedStatement> queryStatements;
+ transient volatile Map<String, Integer> thriftQueryIds;
+
+ private void init(StressYaml yaml) throws RequestValidationException
+ {
+ keyspaceName = yaml.keyspace;
+ keyspaceCql = yaml.keyspace_definition;
+ tableName = yaml.table;
+ tableCql = yaml.table_definition;
+ seedStr = yaml.seed;
+ queries = yaml.queries;
+ insert = yaml.insert;
+
+ assert keyspaceName != null : "keyspace name is required in yaml file";
+ assert tableName != null : "table name is required in yaml file";
+ assert queries != null : "queries map is required in yaml file";
+
+ if (keyspaceCql != null && keyspaceCql.length() > 0)
+ {
+ String name = ((CreateKeyspaceStatement) QueryProcessor.parseStatement(keyspaceCql)).keyspace();
+ assert name.equalsIgnoreCase(keyspaceName) : "Name in keyspace_definition doesn't match keyspace property: '" + name + "' != '" + keyspaceName + "'";
+ }
+ else
+ {
+ keyspaceCql = null;
+ }
+
+ if (tableCql != null && tableCql.length() > 0)
+ {
+ String name = CFMetaData.compile(tableCql, keyspaceName).cfName;
+ assert name.equalsIgnoreCase(tableName) : "Name in table_definition doesn't match table property: '" + name + "' != '" + tableName + "'";
+ }
+ else
+ {
+ tableCql = null;
+ }
+
+ columnConfigs = new HashMap<>();
+ for (Map<String,Object> spec : yaml.columnspec)
+ {
+ lowerCase(spec);
+ String name = (String) spec.remove("name");
+ DistributionFactory population = !spec.containsKey("population") ? null : OptionDistribution.get((String) spec.remove("population"));
+ DistributionFactory size = !spec.containsKey("size") ? null : OptionDistribution.get((String) spec.remove("size"));
+ DistributionFactory clustering = !spec.containsKey("cluster") ? null : OptionDistribution.get((String) spec.remove("cluster"));
+
+ if (!spec.isEmpty())
+ throw new IllegalArgumentException("Unrecognised option(s) in column spec: " + spec);
+ if (name == null)
+ throw new IllegalArgumentException("Missing name argument in column spec");
+
+ GeneratorConfig config = new GeneratorConfig(yaml.seed + name, clustering, size, population);
+ columnConfigs.put(name, config);
+ }
+ }
+
+ public void maybeCreateSchema(StressSettings settings)
+ {
+ JavaDriverClient client = settings.getJavaDriverClient(false);
+
+ if (keyspaceCql != null)
+ {
+ try
+ {
+ client.execute(keyspaceCql, org.apache.cassandra.db.ConsistencyLevel.ONE);
+ }
+ catch (AlreadyExistsException e)
+ {
+ }
+ }
+
+ client.execute("use "+keyspaceName, org.apache.cassandra.db.ConsistencyLevel.ONE);
+
+ if (tableCql != null)
+ {
+ try
+ {
+ client.execute(tableCql, org.apache.cassandra.db.ConsistencyLevel.ONE);
+ }
+ catch (AlreadyExistsException e)
+ {
+ }
+
+ System.out.println(String.format("Created schema. Sleeping %ss for propagation.", settings.node.nodes.size()));
+ Uninterruptibles.sleepUninterruptibly(settings.node.nodes.size(), TimeUnit.SECONDS);
+ }
+
+ maybeLoadSchemaInfo(settings);
+ }
+
+
+ private void maybeLoadSchemaInfo(StressSettings settings)
+ {
+ if (tableMetaData == null)
+ {
+ JavaDriverClient client = settings.getJavaDriverClient();
+
+ synchronized (client)
+ {
+
+ if (tableMetaData != null)
+ return;
+
+ TableMetadata metadata = client.getCluster()
+ .getMetadata()
+ .getKeyspace(keyspaceName)
+ .getTable(tableName);
+
+ //Fill in missing column configs
+ for (ColumnMetadata col : metadata.getColumns())
+ {
+ if (columnConfigs.containsKey(col.getName()))
+ continue;
+
+ columnConfigs.put(col.getName(), new GeneratorConfig(seedStr + col.getName(), null, null, null));
+ }
+
+ tableMetaData = metadata;
+ }
+ }
+ }
+
+ public SchemaQuery getQuery(String name, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ if (queryStatements == null)
+ {
+ synchronized (this)
+ {
+ if (queryStatements == null)
+ {
+ try
+ {
+ JavaDriverClient jclient = settings.getJavaDriverClient();
+ ThriftClient tclient = settings.getThriftClient();
+ Map<String, PreparedStatement> stmts = new HashMap<>();
+ Map<String, Integer> tids = new HashMap<>();
+ for (Map.Entry<String, String> e : queries.entrySet())
+ {
+ stmts.put(e.getKey().toLowerCase(), jclient.prepare(e.getValue()));
+ tids.put(e.getKey().toLowerCase(), tclient.prepare_cql3_query(e.getValue(), Compression.NONE));
+ }
+ thriftQueryIds = tids;
+ queryStatements = stmts;
+ }
+ catch (TException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+ // TODO validation
+ name = name.toLowerCase();
+ return new SchemaQuery(timer, generator, settings, thriftQueryIds.get(name), queryStatements.get(name), ThriftConversion.fromThrift(settings.command.consistencyLevel), ValidationType.NOT_FAIL);
+ }
+
+ public SchemaInsert getInsert(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ if (insertStatement == null)
+ {
+ synchronized (this)
+ {
+ if (insertStatement == null)
+ {
+ maybeLoadSchemaInfo(settings);
+
+ Set<ColumnMetadata> keyColumns = com.google.common.collect.Sets.newHashSet(tableMetaData.getPrimaryKey());
+
+ //Non PK Columns
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("UPDATE \"").append(tableName).append("\" SET ");
+
+ //PK Columns
+ StringBuilder pred = new StringBuilder();
+ pred.append(" WHERE ");
+
+ boolean firstCol = true;
+ boolean firstPred = true;
+ for (ColumnMetadata c : tableMetaData.getColumns())
+ {
+
+ if (keyColumns.contains(c))
+ {
+ if (firstPred)
+ firstPred = false;
+ else
+ pred.append(" AND ");
+
+ pred.append(c.getName()).append(" = ?");
+ }
+ else
+ {
+ if (firstCol)
+ firstCol = false;
+ else
+ sb.append(",");
+
+ sb.append(c.getName()).append(" = ");
+
+ switch (c.getType().getName())
+ {
+ case SET:
+ case LIST:
+ case COUNTER:
+ sb.append(c.getName()).append(" + ?");
+ break;
+ default:
+ sb.append("?");
+ break;
+ }
+ }
+ }
+
+ //Put PK predicates at the end
+ sb.append(pred);
+
+ if (insert == null)
+ insert = new HashMap<>();
+ lowerCase(insert);
+
+ partitions = OptionDistribution.get(!insert.containsKey("partitions") ? "fixed(1)" : insert.remove("partitions"));
+ pervisit = OptionRatioDistribution.get(!insert.containsKey("pervisit") ? "fixed(1)/1" : insert.remove("pervisit"));
+ perbatch = OptionRatioDistribution.get(!insert.containsKey("perbatch") ? "fixed(1)/1" : insert.remove("perbatch"));
+ batchType = !insert.containsKey("batchtype") ? BatchStatement.Type.UNLOGGED : BatchStatement.Type.valueOf(insert.remove("batchtype"));
+ if (!insert.isEmpty())
+ throw new IllegalArgumentException("Unrecognised insert option(s): " + insert);
+
+ if (generator.maxRowCount > 100 * 1000 * 1000)
+ System.err.printf("WARNING: You have defined a schema that permits very large partitions (%.0f max rows (>100M))\n", generator.maxRowCount);
+ if (perbatch.get().max() * pervisit.get().max() * partitions.get().maxValue() * generator.maxRowCount > 100000)
+ System.err.printf("WARNING: You have defined a schema that permits very large batches (%.0f max rows (>100K)). This may OOM this stress client, or the server.\n",
+ perbatch.get().max() * pervisit.get().max() * partitions.get().maxValue() * generator.maxRowCount);
+
+ JavaDriverClient client = settings.getJavaDriverClient();
+ String query = sb.toString();
+ try
+ {
+ thriftInsertId = settings.getThriftClient().prepare_cql3_query(query, Compression.NONE);
+ }
+ catch (TException e)
+ {
+ throw new RuntimeException(e);
+ }
+ insertStatement = client.prepare(query);
+ }
+ }
+ }
+
+ return new SchemaInsert(timer, generator, settings, partitions.get(), pervisit.get(), perbatch.get(), thriftInsertId, insertStatement, ThriftConversion.fromThrift(settings.command.consistencyLevel), batchType);
+ }
+
+ public PartitionGenerator newGenerator(StressSettings settings)
+ {
+ if (generatorFactory == null)
+ {
+ synchronized (this)
+ {
+ maybeLoadSchemaInfo(settings);
+ if (generatorFactory == null)
+ generatorFactory = new GeneratorFactory();
+ }
+ }
+
+ return generatorFactory.newGenerator();
+ }
+
+ private class GeneratorFactory
+ {
+ final List<ColumnInfo> partitionKeys = new ArrayList<>();
+ final List<ColumnInfo> clusteringColumns = new ArrayList<>();
+ final List<ColumnInfo> valueColumns = new ArrayList<>();
+
+ private GeneratorFactory()
+ {
+ Set<ColumnMetadata> keyColumns = com.google.common.collect.Sets.newHashSet(tableMetaData.getPrimaryKey());
+
+ for (ColumnMetadata metadata : tableMetaData.getPartitionKey())
+ partitionKeys.add(new ColumnInfo(metadata.getName(), metadata.getType(), columnConfigs.get(metadata.getName())));
+ for (ColumnMetadata metadata : tableMetaData.getClusteringColumns())
+ clusteringColumns.add(new ColumnInfo(metadata.getName(), metadata.getType(), columnConfigs.get(metadata.getName())));
+ for (ColumnMetadata metadata : tableMetaData.getColumns())
+ if (!keyColumns.contains(metadata))
+ valueColumns.add(new ColumnInfo(metadata.getName(), metadata.getType(), columnConfigs.get(metadata.getName())));
+ }
+
+ PartitionGenerator newGenerator()
+ {
+ return new PartitionGenerator(get(partitionKeys), get(clusteringColumns), get(valueColumns));
+ }
+
+ List<Generator> get(List<ColumnInfo> columnInfos)
+ {
+ List<Generator> result = new ArrayList<>();
+ for (ColumnInfo columnInfo : columnInfos)
+ result.add(columnInfo.getGenerator());
+ return result;
+ }
+ }
+
+ static class ColumnInfo
+ {
+ final String name;
+ final DataType type;
+ final GeneratorConfig config;
+
+ ColumnInfo(String name, DataType type, GeneratorConfig config)
+ {
+ this.name = name;
+ this.type = type;
+ this.config = config;
+ }
+
+ Generator getGenerator()
+ {
+ return getGenerator(name, type, config);
+ }
+
+ static Generator getGenerator(final String name, final DataType type, GeneratorConfig config)
+ {
+ switch (type.getName())
+ {
+ case ASCII:
+ case TEXT:
+ case VARCHAR:
+ return new Strings(name, config);
+ case BIGINT:
+ case COUNTER:
+ return new Longs(name, config);
+ case BLOB:
+ return new Bytes(name, config);
+ case BOOLEAN:
+ return new Booleans(name, config);
+ case DECIMAL:
+ case DOUBLE:
+ return new Doubles(name, config);
+ case FLOAT:
+ return new Floats(name, config);
+ case INET:
+ return new Inets(name, config);
+ case INT:
+ case VARINT:
+ return new Integers(name, config);
+ case TIMESTAMP:
+ return new Dates(name, config);
+ case UUID:
+ return new UUIDs(name, config);
+ case TIMEUUID:
+ return new TimeUUIDs(name, config);
+ case SET:
+ return new Sets(name, getGenerator(name, type.getTypeArguments().get(0), config), config);
+ case LIST:
+ return new Lists(name, getGenerator(name, type.getTypeArguments().get(0), config), config);
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+
+ public static StressProfile load(File file) throws IOError
+ {
+ try
+ {
+ byte[] profileBytes = Files.readAllBytes(Paths.get(file.toURI()));
+
+ Constructor constructor = new Constructor(StressYaml.class);
+
+ Yaml yaml = new Yaml(constructor);
+
+ StressYaml profileYaml = yaml.loadAs(new ByteArrayInputStream(profileBytes), StressYaml.class);
+
+ StressProfile profile = new StressProfile();
+ profile.init(profileYaml);
+
+ return profile;
+ }
+ catch (YAMLException | IOException | RequestValidationException e)
+ {
+ throw new IOError(e);
+ }
+ }
+
+ static <V> void lowerCase(Map<String, V> map)
+ {
+ List<Map.Entry<String, V>> reinsert = new ArrayList<>();
+ Iterator<Map.Entry<String, V>> iter = map.entrySet().iterator();
+ while (iter.hasNext())
+ {
+ Map.Entry<String, V> e = iter.next();
+ if (!e.getKey().toLowerCase().equalsIgnoreCase(e.getKey()))
+ {
+ reinsert.add(e);
+ iter.remove();
+ }
+ }
+ for (Map.Entry<String, V> e : reinsert)
+ map.put(e.getKey().toLowerCase(), e.getValue());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/StressYaml.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressYaml.java b/tools/stress/src/org/apache/cassandra/stress/StressYaml.java
new file mode 100644
index 0000000..e94fa77
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/StressYaml.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress;
+
+import java.util.List;
+import java.util.Map;
+
+public class StressYaml
+{
+ public String seed;
+ public String keyspace;
+ public String keyspace_definition;
+ public String table;
+ public String table_definition;
+
+ public List<Map<String,Object>> columnspec;
+ public Map<String,String> queries;
+ public Map<String,String> insert;
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/Distribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/Distribution.java b/tools/stress/src/org/apache/cassandra/stress/generate/Distribution.java
new file mode 100644
index 0000000..4662454
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/Distribution.java
@@ -0,0 +1,57 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.Serializable;
+
+public abstract class Distribution implements Serializable
+{
+
+ public abstract long next();
+ public abstract double nextDouble();
+ public abstract long inverseCumProb(double cumProb);
+ public abstract void setSeed(long seed);
+
+ public long maxValue()
+ {
+ return inverseCumProb(1d);
+ }
+
+ public long minValue()
+ {
+ return inverseCumProb(0d);
+ }
+
+ // approximation of the average; slightly costly to calculate, so should not be invoked frequently
+ public long average()
+ {
+ double sum = 0;
+ int count = 0;
+ for (float d = 0 ; d <= 1.0d ; d += 0.02d)
+ {
+ sum += inverseCumProb(d);
+ count += 1;
+ }
+ return (long) (sum / count);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionBoundApache.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionBoundApache.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionBoundApache.java
new file mode 100644
index 0000000..23ce3e9
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionBoundApache.java
@@ -0,0 +1,84 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.commons.math3.distribution.AbstractRealDistribution;
+
+public class DistributionBoundApache extends Distribution
+{
+
+ final AbstractRealDistribution delegate;
+ final long min, max;
+
+ public DistributionBoundApache(AbstractRealDistribution delegate, long min, long max)
+ {
+ this.delegate = delegate;
+ this.min = min;
+ this.max = max;
+ }
+
+ @Override
+ public long next()
+ {
+ return bound(min, max, delegate.sample());
+ }
+
+ public double nextDouble()
+ {
+ return boundDouble(min, max, delegate.sample());
+ }
+
+ @Override
+ public long inverseCumProb(double cumProb)
+ {
+ return bound(min, max, delegate.inverseCumulativeProbability(cumProb));
+ }
+
+ public void setSeed(long seed)
+ {
+ delegate.reseedRandomGenerator(seed);
+ }
+
+ private static long bound(long min, long max, double val)
+ {
+ long r = (long) val;
+ if ((r >= min) & (r <= max))
+ return r;
+ if (r < min)
+ return min;
+ if (r > max)
+ return max;
+ throw new IllegalStateException();
+ }
+
+ private static double boundDouble(long min, long max, double r)
+ {
+ if ((r >= min) & (r <= max))
+ return r;
+ if (r < min)
+ return min;
+ if (r > max)
+ return max;
+ throw new IllegalStateException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFactory.java
new file mode 100644
index 0000000..d0dfa89
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFactory.java
@@ -0,0 +1,31 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.Serializable;
+
+public interface DistributionFactory extends Serializable
+{
+
+ Distribution get();
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFixed.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFixed.java
new file mode 100644
index 0000000..bbfb894
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionFixed.java
@@ -0,0 +1,54 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+public class DistributionFixed extends Distribution
+{
+
+ final long key;
+
+ public DistributionFixed(long key)
+ {
+ this.key = key;
+ }
+
+ @Override
+ public long next()
+ {
+ return key;
+ }
+
+ public double nextDouble()
+ {
+ return key;
+ }
+
+ @Override
+ public long inverseCumProb(double cumProb)
+ {
+ return key;
+ }
+
+ public void setSeed(long seed)
+ {
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionInverted.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionInverted.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionInverted.java
new file mode 100644
index 0000000..df52cb8
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionInverted.java
@@ -0,0 +1,37 @@
+package org.apache.cassandra.stress.generate;
+
+public class DistributionInverted extends Distribution
+{
+
+ final Distribution wrapped;
+ final long min;
+ final long max;
+
+ public DistributionInverted(Distribution wrapped)
+ {
+ this.wrapped = wrapped;
+ this.min = wrapped.minValue();
+ this.max = wrapped.maxValue();
+ }
+
+ public long next()
+ {
+ return max - (wrapped.next() - min);
+ }
+
+ public double nextDouble()
+ {
+ return max - (wrapped.nextDouble() - min);
+ }
+
+ public long inverseCumProb(double cumProb)
+ {
+ return max - (wrapped.inverseCumProb(cumProb) - min);
+ }
+
+ public void setSeed(long seed)
+ {
+ wrapped.setSeed(seed);
+ }
+
+}
[03/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java b/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java
index 2782a05..7ede496 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java
@@ -63,8 +63,10 @@ public class SmartThriftClient implements ThriftClient
return r;
r = queryIdCounter.incrementAndGet();
if (queryIds.putIfAbsent(query, r) == null)
+ {
+ queryStrings.put(r, query);
return r;
- queryStrings.put(r, query);
+ }
return queryIds.get(query);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/Timer.java b/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
index 06d113d..45e1ba7 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
@@ -43,7 +43,8 @@ public final class Timer
private int opCount;
// aggregate info
- private int keyCount;
+ private long partitionCount;
+ private long rowCount;
private long total;
private long max;
private long maxStart;
@@ -65,7 +66,7 @@ public final class Timer
return 1 + (index >>> SAMPLE_SIZE_SHIFT);
}
- public void stop(int keys)
+ public void stop(long partitionCount, long rowCount)
{
maybeReport();
long now = System.nanoTime();
@@ -79,7 +80,8 @@ public final class Timer
}
total += time;
opCount += 1;
- keyCount += keys;
+ this.partitionCount += partitionCount;
+ this.rowCount += rowCount;
upToDateAsOf = now;
}
@@ -94,11 +96,12 @@ public final class Timer
( new SampleOfLongs(Arrays.copyOf(sample, index(opCount)), p(opCount)),
new SampleOfLongs(Arrays.copyOfRange(sample, index(opCount), Math.min(opCount, sample.length)), p(opCount) - 1)
);
- final TimingInterval report = new TimingInterval(lastSnap, upToDateAsOf, max, maxStart, max, keyCount, total, opCount,
+ final TimingInterval report = new TimingInterval(lastSnap, upToDateAsOf, max, maxStart, max, partitionCount, rowCount, total, opCount,
SampleOfLongs.merge(rnd, sampleLatencies, Integer.MAX_VALUE));
// reset counters
opCount = 0;
- keyCount = 0;
+ partitionCount = 0;
+ rowCount = 0;
total = 0;
max = 0;
lastSnap = upToDateAsOf;
@@ -145,6 +148,4 @@ public final class Timer
reportRequest = null;
}
}
-
-}
-
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java b/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
index 9e68045..db3fef1 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
@@ -39,7 +39,8 @@ public final class TimingInterval
public final long totalLatency;
// discrete
- public final long keyCount;
+ public final long partitionCount;
+ public final long rowCount;
public final long operationCount;
final SampleOfLongs sample;
@@ -48,16 +49,17 @@ public final class TimingInterval
{
start = end = time;
maxLatency = totalLatency = 0;
- keyCount = operationCount = 0;
+ partitionCount = rowCount = operationCount = 0;
pauseStart = pauseLength = 0;
sample = new SampleOfLongs(new long[0], 1d);
}
- TimingInterval(long start, long end, long maxLatency, long pauseStart, long pauseLength, long keyCount, long totalLatency, long operationCount, SampleOfLongs sample)
+ TimingInterval(long start, long end, long maxLatency, long pauseStart, long pauseLength, long partitionCount, long rowCount, long totalLatency, long operationCount, SampleOfLongs sample)
{
this.start = start;
this.end = Math.max(end, start);
this.maxLatency = maxLatency;
- this.keyCount = keyCount;
+ this.partitionCount = partitionCount;
+ this.rowCount = rowCount;
this.totalLatency = totalLatency;
this.operationCount = operationCount;
this.pauseStart = pauseStart;
@@ -68,7 +70,7 @@ public final class TimingInterval
// merge multiple timer intervals together
static TimingInterval merge(Random rnd, List<TimingInterval> intervals, int maxSamples, long start)
{
- int operationCount = 0, keyCount = 0;
+ long operationCount = 0, partitionCount = 0, rowCount = 0;
long maxLatency = 0, totalLatency = 0;
List<SampleOfLongs> latencies = new ArrayList<>();
long end = 0;
@@ -79,7 +81,8 @@ public final class TimingInterval
operationCount += interval.operationCount;
maxLatency = Math.max(interval.maxLatency, maxLatency);
totalLatency += interval.totalLatency;
- keyCount += interval.keyCount;
+ partitionCount += interval.partitionCount;
+ rowCount += interval.rowCount;
latencies.addAll(Arrays.asList(interval.sample));
if (interval.pauseLength > 0)
{
@@ -89,7 +92,7 @@ public final class TimingInterval
}
if (pauseEnd < pauseStart)
pauseEnd = pauseStart = 0;
- return new TimingInterval(start, end, maxLatency, pauseStart, pauseEnd - pauseStart, keyCount, totalLatency, operationCount,
+ return new TimingInterval(start, end, maxLatency, pauseStart, pauseEnd - pauseStart, partitionCount, rowCount, totalLatency, operationCount,
SampleOfLongs.merge(rnd, latencies, maxSamples));
}
@@ -104,9 +107,14 @@ public final class TimingInterval
return operationCount / ((end - (start + pauseLength)) * 0.000000001d);
}
- public double keyRate()
+ public double partitionRate()
{
- return keyCount / ((end - start) * 0.000000001d);
+ return partitionCount / ((end - start) * 0.000000001d);
+ }
+
+ public double rowRate()
+ {
+ return rowCount / ((end - start) * 0.000000001d);
}
public double meanLatency()
[22/23] git commit: Merge branch 'cassandra-2.1.0' into cassandra-2.1
Posted by be...@apache.org.
Merge branch 'cassandra-2.1.0' into cassandra-2.1
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/35b88c56
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/35b88c56
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/35b88c56
Branch: refs/heads/cassandra-2.1
Commit: 35b88c560f8a294a4502f83901647d34f6532863
Parents: 4e53152 7536429
Author: Benedict Elliott Smith <be...@apache.org>
Authored: Mon Jul 7 18:25:27 2014 +0100
Committer: Benedict Elliott Smith <be...@apache.org>
Committed: Mon Jul 7 18:25:27 2014 +0100
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../cassandra/thrift/ThriftConversion.java | 19 +
.../org/apache/cassandra/utils/UUIDGen.java | 8 +
tools/bin/cassandra-stress | 2 +-
tools/cqlstress-counter-example.yaml | 85 +++
tools/cqlstress-example.yaml | 99 +++
tools/cqlstress-insanity-example.yaml | 102 +++
.../org/apache/cassandra/stress/Operation.java | 218 +-----
.../apache/cassandra/stress/StressAction.java | 262 +++----
.../apache/cassandra/stress/StressMetrics.java | 17 +-
.../apache/cassandra/stress/StressProfile.java | 504 +++++++++++++
.../org/apache/cassandra/stress/StressYaml.java | 38 +
.../cassandra/stress/generate/Distribution.java | 57 ++
.../generate/DistributionBoundApache.java | 84 +++
.../stress/generate/DistributionFactory.java | 31 +
.../stress/generate/DistributionFixed.java | 54 ++
.../stress/generate/DistributionInverted.java | 37 +
.../generate/DistributionOffsetApache.java | 80 +++
.../cassandra/stress/generate/Partition.java | 343 +++++++++
.../stress/generate/PartitionGenerator.java | 80 +++
.../stress/generate/RatioDistribution.java | 25 +
.../generate/RatioDistributionFactory.java | 31 +
.../apache/cassandra/stress/generate/Row.java | 22 +
.../stress/generate/SeedGenerator.java | 8 +
.../stress/generate/SeedRandomGenerator.java | 33 +
.../stress/generate/SeedSeriesGenerator.java | 21 +
.../stress/generate/values/Booleans.java | 37 +
.../cassandra/stress/generate/values/Bytes.java | 54 ++
.../cassandra/stress/generate/values/Dates.java | 46 ++
.../stress/generate/values/Doubles.java | 37 +
.../stress/generate/values/Floats.java | 37 +
.../stress/generate/values/Generator.java | 50 ++
.../stress/generate/values/GeneratorConfig.java | 68 ++
.../stress/generate/values/HexBytes.java | 56 ++
.../stress/generate/values/HexStrings.java | 55 ++
.../cassandra/stress/generate/values/Inets.java | 57 ++
.../stress/generate/values/Integers.java | 38 +
.../cassandra/stress/generate/values/Lists.java | 55 ++
.../cassandra/stress/generate/values/Longs.java | 37 +
.../cassandra/stress/generate/values/Sets.java | 54 ++
.../stress/generate/values/Strings.java | 49 ++
.../stress/generate/values/TimeUUIDs.java | 51 ++
.../cassandra/stress/generate/values/UUIDs.java | 39 +
.../cassandra/stress/generatedata/DataGen.java | 39 -
.../stress/generatedata/DataGenBytesRandom.java | 45 --
.../stress/generatedata/DataGenFactory.java | 30 -
.../stress/generatedata/DataGenHex.java | 60 --
.../DataGenHexFromDistribution.java | 66 --
.../generatedata/DataGenHexFromOpIndex.java | 48 --
.../generatedata/DataGenStringDictionary.java | 107 ---
.../generatedata/DataGenStringRepeats.java | 90 ---
.../stress/generatedata/Distribution.java | 40 --
.../generatedata/DistributionBoundApache.java | 63 --
.../generatedata/DistributionFactory.java | 31 -
.../stress/generatedata/DistributionFixed.java | 46 --
.../generatedata/DistributionOffsetApache.java | 61 --
.../generatedata/DistributionSeqBatch.java | 68 --
.../cassandra/stress/generatedata/KeyGen.java | 54 --
.../cassandra/stress/generatedata/RowGen.java | 53 --
.../generatedata/RowGenDistributedSize.java | 116 ---
.../stress/operations/CqlCounterAdder.java | 77 --
.../stress/operations/CqlCounterGetter.java | 69 --
.../operations/CqlIndexedRangeSlicer.java | 118 ---
.../stress/operations/CqlInserter.java | 88 ---
.../stress/operations/CqlMultiGetter.java | 42 --
.../stress/operations/CqlOperation.java | 698 ------------------
.../stress/operations/CqlRangeSlicer.java | 59 --
.../cassandra/stress/operations/CqlReader.java | 91 ---
.../stress/operations/FixedOpDistribution.java | 25 +
.../stress/operations/OpDistribution.java | 11 +
.../operations/OpDistributionFactory.java | 12 +
.../operations/SampledOpDistribution.java | 41 ++
.../SampledOpDistributionFactory.java | 72 ++
.../stress/operations/ThriftCounterAdder.java | 95 ---
.../stress/operations/ThriftCounterGetter.java | 68 --
.../operations/ThriftIndexedRangeSlicer.java | 114 ---
.../stress/operations/ThriftInserter.java | 117 ---
.../stress/operations/ThriftMultiGetter.java | 80 ---
.../stress/operations/ThriftRangeSlicer.java | 85 ---
.../stress/operations/ThriftReader.java | 94 ---
.../operations/predefined/CqlCounterAdder.java | 84 +++
.../operations/predefined/CqlCounterGetter.java | 74 ++
.../operations/predefined/CqlInserter.java | 79 ++
.../operations/predefined/CqlOperation.java | 714 +++++++++++++++++++
.../stress/operations/predefined/CqlReader.java | 87 +++
.../predefined/PredefinedOperation.java | 248 +++++++
.../predefined/ThriftCounterAdder.java | 86 +++
.../predefined/ThriftCounterGetter.java | 66 ++
.../operations/predefined/ThriftInserter.java | 96 +++
.../operations/predefined/ThriftReader.java | 79 ++
.../operations/userdefined/SchemaInsert.java | 144 ++++
.../operations/userdefined/SchemaQuery.java | 86 +++
.../operations/userdefined/SchemaStatement.java | 164 +++++
.../cassandra/stress/settings/Command.java | 24 +-
.../stress/settings/CommandCategory.java | 4 +-
.../stress/settings/OptionAnyProbabilities.java | 78 ++
.../stress/settings/OptionDataGen.java | 203 ------
.../stress/settings/OptionDistribution.java | 75 +-
.../settings/OptionEnumProbabilities.java | 62 ++
.../cassandra/stress/settings/OptionMulti.java | 3 +-
.../settings/OptionRatioDistribution.java | 166 +++++
.../cassandra/stress/settings/OptionSimple.java | 5 +-
.../stress/settings/SettingsColumn.java | 50 +-
.../stress/settings/SettingsCommand.java | 58 +-
.../stress/settings/SettingsCommandMixed.java | 207 ------
.../settings/SettingsCommandPreDefined.java | 145 ++++
.../SettingsCommandPreDefinedMixed.java | 151 ++++
.../stress/settings/SettingsCommandUser.java | 135 ++++
.../cassandra/stress/settings/SettingsKey.java | 27 +-
.../cassandra/stress/settings/SettingsMisc.java | 2 +-
.../cassandra/stress/settings/SettingsMode.java | 6 +-
.../stress/settings/SettingsSchema.java | 77 +-
.../stress/settings/SettingsTransport.java | 2 +-
.../stress/settings/StressSettings.java | 36 +-
.../stress/settings/ValidationType.java | 8 +
.../cassandra/stress/util/JavaDriverClient.java | 19 +-
.../stress/util/SmartThriftClient.java | 4 +-
.../org/apache/cassandra/stress/util/Timer.java | 17 +-
.../cassandra/stress/util/TimingInterval.java | 26 +-
119 files changed, 5861 insertions(+), 3890 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/35b88c56/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 682f599,ff2f586..a0983af
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,10 -1,5 +1,11 @@@
+2.1.1
+ * Improve schema merge performance (CASSANDRA-7444)
+ * Fix NPE when unknown prepared statement ID is used (CASSANDRA-7454)
+ * Adjust MT depth based on # of partition validating (CASSANDRA-5263)
+ * Optimise NativeCell comparisons (CASSANDRA-6755)
+
2.1.0-rc3
+ * Introduce CQL support for stress tool (CASSANDRA-6146)
* Fix ClassCastException processing expired messages (CASSANDRA-7496)
* Fix prepared marker for collections inside UDT (CASSANDRA-7472)
* Remove left-over populate_io_cache_on_flush and replicate_on_write
[06/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionOffsetApache.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionOffsetApache.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionOffsetApache.java
deleted file mode 100644
index cfbc385..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionOffsetApache.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import org.apache.commons.math3.distribution.AbstractRealDistribution;
-
-public class DistributionOffsetApache extends Distribution
-{
-
- final AbstractRealDistribution delegate;
- final long min, delta;
-
- public DistributionOffsetApache(AbstractRealDistribution delegate, long min, long max)
- {
- this.delegate = delegate;
- this.min = min;
- this.delta = max - min;
- }
-
- @Override
- public long next()
- {
- return offset(min, delta, delegate.sample());
- }
-
- @Override
- public long inverseCumProb(double cumProb)
- {
- return offset(min, delta, delegate.inverseCumulativeProbability(cumProb));
- }
-
- private long offset(long min, long delta, double val)
- {
- long r = (long) val;
- if (r < 0)
- r = 0;
- if (r > delta)
- r = delta;
- return min + r;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionSeqBatch.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionSeqBatch.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionSeqBatch.java
deleted file mode 100644
index 8e1a5d5..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionSeqBatch.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-public class DistributionSeqBatch extends DataGenHex
-{
-
- final Distribution delegate;
- final int batchSize;
- final long maxKey;
-
- private int batchIndex;
- private long batchKey;
-
- // object must be published safely if passed between threadCount, due to batchIndex not being volatile. various
- // hacks possible, but not ideal. don't want to use volatile as object intended for single threaded use.
- public DistributionSeqBatch(int batchSize, long maxKey, Distribution delegate)
- {
- this.batchIndex = batchSize;
- this.batchSize = batchSize;
- this.maxKey = maxKey;
- this.delegate = delegate;
- }
-
- @Override
- long next(long operationIndex)
- {
- if (batchIndex >= batchSize)
- {
- batchKey = delegate.next();
- batchIndex = 0;
- }
- long r = batchKey + batchIndex++;
- if (r > maxKey)
- {
- batchKey = delegate.next();
- batchIndex = 1;
- r = batchKey;
- }
- return r;
- }
-
- @Override
- public boolean isDeterministic()
- {
- return false;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/KeyGen.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/KeyGen.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/KeyGen.java
deleted file mode 100644
index dad5918..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/KeyGen.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-
-public class KeyGen
-{
-
- final DataGen dataGen;
- final int keySize;
- final List<ByteBuffer> keyBuffers = new ArrayList<>();
-
- public KeyGen(DataGen dataGen, int keySize)
- {
- this.dataGen = dataGen;
- this.keySize = keySize;
- }
-
- public List<ByteBuffer> getKeys(int n, long index)
- {
- while (keyBuffers.size() < n)
- keyBuffers.add(ByteBuffer.wrap(new byte[keySize]));
- dataGen.generate(keyBuffers, index, null);
- return keyBuffers;
- }
-
- public boolean isDeterministic()
- {
- return dataGen.isDeterministic();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java
deleted file mode 100644
index 9c6ca43..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGen.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.List;
-
-/**
- * Generates a row of data, by constructing one byte buffers per column according to some algorithm
- * and delegating the work of populating the values of those byte buffers to the provided data generator
- */
-public abstract class RowGen
-{
-
- final DataGen dataGen;
- protected RowGen(DataGen dataGenerator)
- {
- this.dataGen = dataGenerator;
- }
-
- public List<ByteBuffer> generate(long operationIndex, ByteBuffer key)
- {
- List<ByteBuffer> fill = getColumns(operationIndex);
- dataGen.generate(fill, operationIndex, key);
- return fill;
- }
-
- // these byte[] may be re-used
- abstract List<ByteBuffer> getColumns(long operationIndex);
- abstract public int count(long operationIndex);
-
- abstract public boolean isDeterministic();
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java
deleted file mode 100644
index fffad2f..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/RowGenDistributedSize.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-public class RowGenDistributedSize extends RowGen
-{
-
- // TODO - make configurable
- static final int MAX_SINGLE_CACHE_SIZE = 16 * 1024;
-
- final Distribution countDistribution;
- final Distribution sizeDistribution;
-
- final TreeMap<Integer, ByteBuffer> cache = new TreeMap<>();
-
- // array re-used for returning columns
- final ByteBuffer[] ret;
- final int[] sizes;
-
- final boolean isDeterministic;
-
- public RowGenDistributedSize(DataGen dataGenerator, Distribution countDistribution, Distribution sizeDistribution)
- {
- super(dataGenerator);
- this.countDistribution = countDistribution;
- 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();
- }
-
- ByteBuffer getBuffer(int size)
- {
- if (size >= MAX_SINGLE_CACHE_SIZE)
- return ByteBuffer.allocate(size);
- Map.Entry<Integer, ByteBuffer> found = cache.ceilingEntry(size);
- if (found == null)
- {
- // remove the next entry down, and replace it with a cache of this size
- Integer del = cache.lowerKey(size);
- if (del != null)
- cache.remove(del);
- return ByteBuffer.allocate(size);
- }
- ByteBuffer r = found.getValue();
- cache.remove(found.getKey());
- return r;
- }
-
- @Override
- List<ByteBuffer> getColumns(long operationIndex)
- {
- int i = 0;
- int count = (int) countDistribution.next();
- while (i < count)
- {
- int columnSize = (int) sizeDistribution.next();
- sizes[i] = columnSize;
- ret[i] = getBuffer(columnSize);
- i++;
- }
- while (i < ret.length && ret[i] != null)
- ret[i] = null;
- i = 0;
- while (i < count)
- {
- ByteBuffer b = ret[i];
- cache.put(b.capacity(), b);
- b.position(b.capacity() - sizes[i]);
- ret[i] = b.slice();
- b.position(0);
- i++;
- }
- return Arrays.asList(ret).subList(0, count);
- }
-
- public int count(long operationIndex)
- {
- return (int) countDistribution.next();
- }
-
- @Override
- public boolean isDeterministic()
- {
- return isDeterministic;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java
deleted file mode 100644
index 9a8c37d..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterAdder.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-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<Integer>
-{
- public CqlCounterAdder(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected String buildQuery()
- {
- String counterCF = state.isCql2() ? state.type.table : "Counter3";
-
- StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(counterCF));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- query.append(" SET ");
-
- // TODO : increment distribution subset of columns
- for (int i = 0; i < state.settings.columns.maxColumnsPerKey; i++)
- {
- if (i > 0)
- query.append(",");
-
- query.append('C').append(i).append("=C").append(i).append("+?");
- }
- query.append(" WHERE KEY=?");
- return query.toString();
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- final List<Object> 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<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new CqlRunOpAlwaysSucceed(client, query, queryId, params, keyid, key, 1);
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java
deleted file mode 100644
index 88d622e..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlCounterGetter.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.List;
-
-public class CqlCounterGetter extends CqlOperation<Integer>
-{
-
- public CqlCounterGetter(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- return Collections.<Object>singletonList(ByteBuffer.wrap(key));
- }
-
- @Override
- protected String buildQuery()
- {
- 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() ? state.type.table : "Counter3";
-
- query.append(" FROM ").append(wrapInQuotesIfRequired(counterCF));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- return query.append(" WHERE KEY=?").toString();
- }
-
- @Override
- protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new CqlRunOpTestNonEmpty(client, query, queryId, params, keyid, key);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java
deleted file mode 100644
index 046381e..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
-*
-* 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.
-*
-*/
-
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.cassandra.utils.FBUtilities;
-
-public class CqlIndexedRangeSlicer extends CqlOperation<byte[][]>
-{
-
- volatile boolean acceptNoResults = false;
-
- public CqlIndexedRangeSlicer(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected String buildQuery()
- {
- StringBuilder query = new StringBuilder("SELECT");
- query.append(wrapInQuotesIfRequired("key"));
- query.append(" FROM ");
- query.append(wrapInQuotesIfRequired(state.type.table));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- final String columnName = (state.settings.columns.namestrs.get(1));
- query.append(" WHERE ").append(columnName).append("=?")
- .append(" AND KEY > ? LIMIT ").append(state.settings.command.keysAtOnce);
- return query.toString();
- }
-
- @Override
- protected void run(CqlOperation.ClientWrapper client) throws IOException
- {
- acceptNoResults = false;
- final List<ByteBuffer> columns = generateColumnValues(getKey());
- final ByteBuffer value = columns.get(1); // only C1 column is indexed
- byte[] minKey = new byte[0];
- int rowCount;
- do
- {
- List<Object> params = Arrays.<Object>asList(value, ByteBuffer.wrap(minKey));
- CqlRunOp<byte[][]> op = run(client, params, value, new String(value.array()));
- byte[][] keys = op.result;
- rowCount = keys.length;
- minKey = getNextMinKey(minKey, keys);
- acceptNoResults = true;
- } while (rowCount > 0);
- }
-
- private final class IndexedRangeSliceRunOp extends CqlRunOpFetchKeys
- {
-
- protected IndexedRangeSliceRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- super(client, query, queryId, params, keyid, key);
- }
-
- @Override
- public boolean validate(byte[][] result)
- {
- return acceptNoResults || result.length > 0;
- }
- }
-
- @Override
- protected CqlRunOp<byte[][]> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new IndexedRangeSliceRunOp(client, query, queryId, params, keyid, key);
- }
-
- private static byte[] getNextMinKey(byte[] cur, byte[][] keys)
- {
- // find max
- for (byte[] key : keys)
- if (FBUtilities.compareUnsigned(cur, key) < 0)
- cur = key;
-
- // increment
- for (int i = 0 ; i < cur.length ; i++)
- if (++cur[i] != 0)
- break;
- return cur;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java
deleted file mode 100644
index 71cdadf..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.cassandra.utils.UUIDGen;
-
-public class CqlInserter extends CqlOperation<Integer>
-{
-
- 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.type.table));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- query.append(" SET ");
-
- for (int i = 0 ; i < state.settings.columns.maxColumnsPerKey; i++)
- {
- if (i > 0)
- query.append(',');
-
- if (state.settings.columns.useTimeUUIDComparator)
- {
- if (state.isCql3())
- throw new UnsupportedOperationException("Cannot use UUIDs in column names with CQL3");
-
- query.append(wrapInQuotesIfRequired(UUIDGen.getTimeUUID().toString()))
- .append(" = ?");
- }
- else
- {
- query.append(wrapInQuotesIfRequired("C" + i)).append(" = ?");
- }
- }
-
- query.append(" WHERE KEY=?");
- return query.toString();
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- final ArrayList<Object> queryParams = new ArrayList<>();
- final List<ByteBuffer> values = generateColumnValues(ByteBuffer.wrap(key));
- queryParams.addAll(values);
- queryParams.add(ByteBuffer.wrap(key));
- return queryParams;
- }
-
- @Override
- protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new CqlRunOpAlwaysSucceed(client, query, queryId, params, keyid, key, 1);
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlMultiGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlMultiGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlMultiGetter.java
deleted file mode 100644
index 80a7118..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlMultiGetter.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.IOException;
-
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.util.ThriftClient;
-
-public class CqlMultiGetter extends Operation
-{
- public CqlMultiGetter(State state, long idx)
- {
- super(state, idx);
- throw new RuntimeException("Multiget is not implemented for CQL");
- }
-
- @Override
- public void run(ThriftClient client) throws IOException
- {
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java
deleted file mode 100644
index 1c59e2d..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlOperation.java
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import com.datastax.driver.core.PreparedStatement;
-import com.datastax.driver.core.ResultSet;
-import com.datastax.driver.core.Row;
-import com.google.common.base.Function;
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.settings.ConnectionStyle;
-import org.apache.cassandra.stress.settings.CqlVersion;
-import org.apache.cassandra.stress.util.JavaDriverClient;
-import org.apache.cassandra.stress.util.ThriftClient;
-import org.apache.cassandra.thrift.Compression;
-import org.apache.cassandra.thrift.CqlResult;
-import org.apache.cassandra.thrift.CqlRow;
-import org.apache.cassandra.thrift.ThriftConversion;
-import org.apache.cassandra.transport.SimpleClient;
-import org.apache.cassandra.transport.messages.ResultMessage;
-import org.apache.cassandra.utils.ByteBufferUtil;
-import org.apache.thrift.TException;
-
-public abstract class CqlOperation<V> extends Operation
-{
-
- protected abstract List<Object> getQueryParameters(byte[] key);
- protected abstract String buildQuery();
- protected abstract CqlRunOp<V> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String id, ByteBuffer key);
-
- public CqlOperation(State state, long idx)
- {
- super(state, idx);
- if (state.settings.columns.useSuperColumns)
- 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<V> run(final ClientWrapper client, final List<Object> queryParams, final ByteBuffer key, final String keyid) throws IOException
- {
- final CqlRunOp<V> op;
- if (state.settings.mode.style == ConnectionStyle.CQL_PREPARED)
- {
- final Object id;
- Object idobj = state.getCqlCache();
- if (idobj == null)
- {
- try
- {
- id = client.createPreparedStatement(buildQuery());
- } catch (TException e)
- {
- throw new RuntimeException(e);
- }
- state.storeCqlCache(id);
- }
- else
- id = idobj;
-
- op = buildRunOp(client, null, id, queryParams, keyid, key);
- }
- else
- {
- final String query;
- Object qobj = state.getCqlCache();
- if (qobj == null)
- state.storeCqlCache(query = buildQuery());
- else
- query = qobj.toString();
-
- op = buildRunOp(client, query, null, queryParams, keyid, key);
- }
-
- timeWithRetry(op);
- return op;
- }
-
- protected void run(final ClientWrapper client) throws IOException
- {
- final byte[] key = getKey().array();
- final List<Object> queryParams = getQueryParameters(key);
- run(client, queryParams, ByteBuffer.wrap(key), new String(key));
- }
-
- // Classes to process Cql results
-
- // Always succeeds so long as the query executes without error; provides a keyCount to increment on instantiation
- protected final class CqlRunOpAlwaysSucceed extends CqlRunOp<Integer>
- {
-
- final int keyCount;
-
- protected CqlRunOpAlwaysSucceed(ClientWrapper client, String query, Object queryId, List<Object> params, String id, ByteBuffer key, int keyCount)
- {
- super(client, query, queryId, RowCountHandler.INSTANCE, params, id, key);
- this.keyCount = keyCount;
- }
-
- @Override
- public boolean validate(Integer result)
- {
- return true;
- }
-
- @Override
- public int keyCount()
- {
- return keyCount;
- }
- }
-
- // Succeeds so long as the result set is nonempty, and the query executes without error
- protected final class CqlRunOpTestNonEmpty extends CqlRunOp<Integer>
- {
-
- protected CqlRunOpTestNonEmpty(ClientWrapper client, String query, Object queryId, List<Object> params, String id, ByteBuffer key)
- {
- super(client, query, queryId, RowCountHandler.INSTANCE, params, id, key);
- }
-
- @Override
- public boolean validate(Integer result)
- {
- return result > 0;
- }
-
- @Override
- public int keyCount()
- {
- return result;
- }
- }
-
- // Requires a custom validate() method, but fetches and stores the keys from the result set for further processing
- protected abstract class CqlRunOpFetchKeys extends CqlRunOp<byte[][]>
- {
-
- protected CqlRunOpFetchKeys(ClientWrapper client, String query, Object queryId, List<Object> params, String id, ByteBuffer key)
- {
- super(client, query, queryId, KeysHandler.INSTANCE, params, id, key);
- }
-
- @Override
- public int keyCount()
- {
- return result.length;
- }
-
- }
-
- protected final class CqlRunOpMatchResults extends CqlRunOp<ByteBuffer[][]>
- {
-
- final List<List<ByteBuffer>> 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<Object> params, String id, ByteBuffer key, List<List<ByteBuffer>> expect)
- {
- super(client, query, queryId, RowsHandler.INSTANCE, params, id, key);
- this.expect = expect;
- }
-
- @Override
- public int keyCount()
- {
- return result == null ? 0 : result.length;
- }
-
- public boolean validate(ByteBuffer[][] result)
- {
- if (result.length != expect.size())
- return false;
- for (int i = 0 ; i < result.length ; i++)
- if (expect.get(i) != null && !expect.get(i).equals(Arrays.asList(result[i])))
- return false;
- return true;
- }
- }
-
- // Cql
- protected abstract class CqlRunOp<V> implements RunOp
- {
-
- final ClientWrapper client;
- final String query;
- final Object queryId;
- final List<Object> params;
- final String id;
- final ByteBuffer key;
- final ResultHandler<V> handler;
- V result;
-
- private CqlRunOp(ClientWrapper client, String query, Object queryId, ResultHandler<V> handler, List<Object> params, String id, ByteBuffer key)
- {
- this.client = client;
- this.query = query;
- this.queryId = queryId;
- this.handler = handler;
- this.params = params;
- this.id = id;
- this.key = key;
- }
-
- @Override
- public boolean run() throws Exception
- {
- return queryId != null
- ? validate(result = client.execute(queryId, key, params, handler))
- : validate(result = client.execute(query, key, params, handler));
- }
-
- @Override
- public String key()
- {
- return id;
- }
-
- public abstract boolean validate(V result);
-
- }
-
-
- /// LOTS OF WRAPPING/UNWRAPPING NONSENSE
-
-
- @Override
- public void run(final ThriftClient client) throws IOException
- {
- run(wrap(client));
- }
-
- @Override
- public void run(SimpleClient client) throws IOException
- {
- run(wrap(client));
- }
-
- @Override
- public void run(JavaDriverClient client) throws IOException
- {
- run(wrap(client));
- }
-
- public ClientWrapper wrap(ThriftClient client)
- {
- return state.isCql3()
- ? new Cql3CassandraClientWrapper(client)
- : new Cql2CassandraClientWrapper(client);
-
- }
-
- public ClientWrapper wrap(JavaDriverClient client)
- {
- return new JavaDriverWrapper(client);
- }
-
- public ClientWrapper wrap(SimpleClient client)
- {
- return new SimpleClientWrapper(client);
- }
-
- protected interface ClientWrapper
- {
- Object createPreparedStatement(String cqlQuery) throws TException;
- <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
- <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
- }
-
- private final class JavaDriverWrapper implements ClientWrapper
- {
- final JavaDriverClient client;
- private JavaDriverWrapper(JavaDriverClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
- {
- String formattedQuery = formatCqlQuery(query, queryParams, state.isCql3());
- return handler.javaDriverHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(state.settings.command.consistencyLevel)));
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
- {
- return handler.javaDriverHandler().apply(
- client.executePrepared(
- (PreparedStatement) preparedStatementId,
- queryParams,
- ThriftConversion.fromThrift(state.settings.command.consistencyLevel)));
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery)
- {
- return client.prepare(cqlQuery);
- }
- }
-
- private final class SimpleClientWrapper implements ClientWrapper
- {
- final SimpleClient client;
- private SimpleClientWrapper(SimpleClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
- {
- String formattedQuery = formatCqlQuery(query, queryParams, state.isCql3());
- return handler.thriftHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(state.settings.command.consistencyLevel)));
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
- {
- return handler.thriftHandler().apply(
- client.executePrepared(
- (byte[]) preparedStatementId,
- toByteBufferParams(queryParams),
- ThriftConversion.fromThrift(state.settings.command.consistencyLevel)));
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery)
- {
- return client.prepare(cqlQuery).statementId.bytes;
- }
- }
-
- // client wrapper for Cql3
- private final class Cql3CassandraClientWrapper implements ClientWrapper
- {
- final ThriftClient client;
- private Cql3CassandraClientWrapper(ThriftClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- String formattedQuery = formatCqlQuery(query, queryParams, true);
- return handler.simpleNativeHandler().apply(
- client.execute_cql3_query(formattedQuery, key, Compression.NONE, state.settings.command.consistencyLevel)
- );
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- Integer id = (Integer) preparedStatementId;
- return handler.simpleNativeHandler().apply(
- client.execute_prepared_cql3_query(id, key, toByteBufferParams(queryParams), state.settings.command.consistencyLevel)
- );
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery) throws TException
- {
- return client.prepare_cql3_query(cqlQuery, Compression.NONE);
- }
- }
-
- // client wrapper for Cql2
- private final class Cql2CassandraClientWrapper implements ClientWrapper
- {
- final ThriftClient client;
- private Cql2CassandraClientWrapper(ThriftClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- String formattedQuery = formatCqlQuery(query, queryParams, false);
- return handler.simpleNativeHandler().apply(
- client.execute_cql_query(formattedQuery, key, Compression.NONE)
- );
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- Integer id = (Integer) preparedStatementId;
- return handler.simpleNativeHandler().apply(
- client.execute_prepared_cql_query(id, key, toByteBufferParams(queryParams))
- );
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery) throws TException
- {
- return client.prepare_cql_query(cqlQuery, Compression.NONE);
- }
- }
-
- // interface for building functions to standardise results from each client
- protected static interface ResultHandler<V>
- {
- Function<ResultSet, V> javaDriverHandler();
- Function<ResultMessage, V> thriftHandler();
- Function<CqlResult, V> simpleNativeHandler();
- }
-
- protected static class RowCountHandler implements ResultHandler<Integer>
- {
- static final RowCountHandler INSTANCE = new RowCountHandler();
-
- @Override
- public Function<ResultSet, Integer> javaDriverHandler()
- {
- return new Function<ResultSet, Integer>()
- {
- @Override
- public Integer apply(ResultSet rows)
- {
- if (rows == null)
- return 0;
- return rows.all().size();
- }
- };
- }
-
- @Override
- public Function<ResultMessage, Integer> thriftHandler()
- {
- return new Function<ResultMessage, Integer>()
- {
- @Override
- public Integer apply(ResultMessage result)
- {
- return result instanceof ResultMessage.Rows ? ((ResultMessage.Rows) result).result.size() : 0;
- }
- };
- }
-
- @Override
- public Function<CqlResult, Integer> simpleNativeHandler()
- {
- return new Function<CqlResult, Integer>()
- {
-
- @Override
- public Integer apply(CqlResult result)
- {
- switch (result.getType())
- {
- case ROWS:
- return result.getRows().size();
- default:
- return 1;
- }
- }
- };
- }
-
- }
-
- // Processes results from each client into an array of all key bytes returned
- protected static final class RowsHandler implements ResultHandler<ByteBuffer[][]>
- {
- static final RowsHandler INSTANCE = new RowsHandler();
-
- @Override
- public Function<ResultSet, ByteBuffer[][]> javaDriverHandler()
- {
- return new Function<ResultSet, ByteBuffer[][]>()
- {
-
- @Override
- public ByteBuffer[][] apply(ResultSet result)
- {
- if (result == null)
- return new ByteBuffer[0][];
- List<Row> rows = result.all();
-
- ByteBuffer[][] r = new ByteBuffer[rows.size()][];
- for (int i = 0 ; i < r.length ; i++)
- {
- Row row = rows.get(i);
- r[i] = new ByteBuffer[row.getColumnDefinitions().size()];
- for (int j = 0 ; j < row.getColumnDefinitions().size() ; j++)
- r[i][j] = row.getBytes(j);
- }
- return r;
- }
- };
- }
-
- @Override
- public Function<ResultMessage, ByteBuffer[][]> thriftHandler()
- {
- return new Function<ResultMessage, ByteBuffer[][]>()
- {
-
- @Override
- public ByteBuffer[][] apply(ResultMessage result)
- {
- if (!(result instanceof ResultMessage.Rows))
- return new ByteBuffer[0][];
-
- ResultMessage.Rows rows = ((ResultMessage.Rows) result);
- ByteBuffer[][] r = new ByteBuffer[rows.result.size()][];
- for (int i = 0 ; i < r.length ; i++)
- {
- List<ByteBuffer> row = rows.result.rows.get(i);
- r[i] = new ByteBuffer[row.size()];
- for (int j = 0 ; j < row.size() ; j++)
- r[i][j] = row.get(j);
- }
- return r;
- }
- };
- }
-
- @Override
- public Function<CqlResult, ByteBuffer[][]> simpleNativeHandler()
- {
- return new Function<CqlResult, ByteBuffer[][]>()
- {
-
- @Override
- public ByteBuffer[][] apply(CqlResult result)
- {
- ByteBuffer[][] r = new ByteBuffer[result.getRows().size()][];
- for (int i = 0 ; i < r.length ; i++)
- {
- CqlRow row = result.getRows().get(i);
- r[i] = new ByteBuffer[row.getColumns().size()];
- for (int j = 0 ; j < r[i].length ; j++)
- r[i][j] = ByteBuffer.wrap(row.getColumns().get(j).getValue());
- }
- return r;
- }
- };
- }
-
- }
- // Processes results from each client into an array of all key bytes returned
- protected static final class KeysHandler implements ResultHandler<byte[][]>
- {
- static final KeysHandler INSTANCE = new KeysHandler();
-
- @Override
- public Function<ResultSet, byte[][]> javaDriverHandler()
- {
- return new Function<ResultSet, byte[][]>()
- {
-
- @Override
- public byte[][] apply(ResultSet result)
- {
-
- if (result == null)
- return new byte[0][];
- List<Row> rows = result.all();
- byte[][] r = new byte[rows.size()][];
- for (int i = 0 ; i < r.length ; i++)
- r[i] = rows.get(i).getBytes(0).array();
- return r;
- }
- };
- }
-
- @Override
- public Function<ResultMessage, byte[][]> thriftHandler()
- {
- return new Function<ResultMessage, byte[][]>()
- {
-
- @Override
- public byte[][] apply(ResultMessage result)
- {
- if (result instanceof ResultMessage.Rows)
- {
- ResultMessage.Rows rows = ((ResultMessage.Rows) result);
- byte[][] r = new byte[rows.result.size()][];
- for (int i = 0 ; i < r.length ; i++)
- r[i] = rows.result.rows.get(i).get(0).array();
- return r;
- }
- return null;
- }
- };
- }
-
- @Override
- public Function<CqlResult, byte[][]> simpleNativeHandler()
- {
- return new Function<CqlResult, byte[][]>()
- {
-
- @Override
- public byte[][] apply(CqlResult result)
- {
- byte[][] r = new byte[result.getRows().size()][];
- for (int i = 0 ; i < r.length ; i++)
- r[i] = result.getRows().get(i).getKey();
- return r;
- }
- };
- }
-
- }
-
- private static String getUnQuotedCqlBlob(ByteBuffer term, boolean isCQL3)
- {
- return isCQL3
- ? "0x" + ByteBufferUtil.bytesToHex(term)
- : ByteBufferUtil.bytesToHex(term);
- }
-
- /**
- * Constructs a CQL query string by replacing instances of the character
- * '?', with the corresponding parameter.
- *
- * @param query base query string to format
- * @param parms sequence of string query parameters
- * @return formatted CQL query string
- */
- private static String formatCqlQuery(String query, List<Object> parms, boolean isCql3)
- {
- int marker, position = 0;
- StringBuilder result = new StringBuilder();
-
- if (-1 == (marker = query.indexOf('?')) || parms.size() == 0)
- return query;
-
- for (Object parm : parms)
- {
- result.append(query.substring(position, marker));
- 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)))
- break;
- }
-
- if (position < query.length())
- result.append(query.substring(position));
-
- return result.toString();
- }
-
- private static List<ByteBuffer> toByteBufferParams(List<Object> params)
- {
- List<ByteBuffer> 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
- ? "\"" + string + "\""
- : string;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java
deleted file mode 100644
index 16cdff3..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.List;
-
-public class CqlRangeSlicer extends CqlOperation<Integer>
-{
- public CqlRangeSlicer(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- return Collections.<Object>singletonList(ByteBuffer.wrap(key));
- }
-
- @Override
- protected String buildQuery()
- {
- StringBuilder query = new StringBuilder("SELECT FIRST ").append(state.settings.columns.maxColumnsPerKey)
- .append(" ''..'' FROM ").append(wrapInQuotesIfRequired(state.type.table));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
-
- return query.append(" WHERE KEY > ?").toString();
- }
-
- @Override
- protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- return new CqlRunOpTestNonEmpty(client, query, queryId, params, keyid, key);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java
deleted file mode 100644
index fb07edc..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlReader.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.apache.cassandra.stress.operations;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.cassandra.utils.ByteBufferUtil;
-
-public class CqlReader extends CqlOperation<ByteBuffer[][]>
-{
-
- public CqlReader(State state, long idx)
- {
- super(state, idx);
- }
-
- @Override
- protected String buildQuery()
- {
- StringBuilder query = new StringBuilder("SELECT ");
-
- if (state.settings.columns.slice)
- {
- if (state.isCql2())
- query.append("FIRST ").append(state.settings.columns.maxColumnsPerKey).append(" ''..''");
- else
- query.append("*");
- }
- else
- {
- try
- {
- for (int i = 0; i < state.settings.columns.names.size() ; i++)
- {
- if (i > 0)
- query.append(",");
- query.append(wrapInQuotesIfRequired(ByteBufferUtil.string(state.settings.columns.names.get(i))));
- }
- }
- catch (CharacterCodingException e)
- {
- throw new IllegalStateException(e);
- }
- }
-
- query.append(" FROM ").append(wrapInQuotesIfRequired(state.type.table));
-
- if (state.isCql2())
- query.append(" USING CONSISTENCY ").append(state.settings.command.consistencyLevel);
- query.append(" WHERE KEY=?");
- return query.toString();
- }
-
- @Override
- protected List<Object> getQueryParameters(byte[] key)
- {
- return Collections.<Object>singletonList(ByteBuffer.wrap(key));
- }
-
- @Override
- protected CqlRunOp<ByteBuffer[][]> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, String keyid, ByteBuffer key)
- {
- List<ByteBuffer> expectRow = state.rowGen.isDeterministic() ? generateColumnValues(key) : null;
- return new CqlRunOpMatchResults(client, query, queryId, params, keyid, key, Arrays.asList(expectRow));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java b/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
new file mode 100644
index 0000000..914d212
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
@@ -0,0 +1,25 @@
+package org.apache.cassandra.stress.operations;
+
+import org.apache.cassandra.stress.Operation;
+
+public class FixedOpDistribution implements OpDistribution
+{
+
+ final Operation operation;
+
+ public FixedOpDistribution(Operation operation)
+ {
+ this.operation = operation;
+ }
+
+ public Operation next()
+ {
+ return operation;
+ }
+
+ public int maxBatchSize()
+ {
+ return (int) operation.partitionCount.maxValue();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
new file mode 100644
index 0000000..a744f18
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
@@ -0,0 +1,11 @@
+package org.apache.cassandra.stress.operations;
+
+import org.apache.cassandra.stress.Operation;
+
+public interface OpDistribution
+{
+
+ Operation next();
+ public int maxBatchSize();
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
new file mode 100644
index 0000000..08d5f56
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
@@ -0,0 +1,12 @@
+package org.apache.cassandra.stress.operations;
+
+import org.apache.cassandra.stress.util.Timer;
+
+public interface OpDistributionFactory
+{
+
+ public OpDistribution get(Timer timer);
+ public String desc();
+ Iterable<OpDistributionFactory> each();
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
new file mode 100644
index 0000000..8bd2806
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
@@ -0,0 +1,41 @@
+package org.apache.cassandra.stress.operations;
+
+import org.apache.commons.math3.distribution.EnumeratedDistribution;
+import org.apache.commons.math3.util.Pair;
+
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.generate.Distribution;
+
+public class SampledOpDistribution implements OpDistribution
+{
+
+ final EnumeratedDistribution<Operation> operations;
+ final Distribution clustering;
+ private Operation cur;
+ private long remaining;
+
+ public SampledOpDistribution(EnumeratedDistribution<Operation> operations, Distribution clustering)
+ {
+ this.operations = operations;
+ this.clustering = clustering;
+ }
+
+ public int maxBatchSize()
+ {
+ int max = 1;
+ for (Pair<Operation, Double> pair : operations.getPmf())
+ max = Math.max(max, (int) pair.getFirst().partitionCount.maxValue());
+ return max;
+ }
+
+ public Operation next()
+ {
+ while (remaining == 0)
+ {
+ remaining = clustering.next();
+ cur = operations.sample();
+ }
+ remaining--;
+ return cur;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
new file mode 100644
index 0000000..575da12
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
@@ -0,0 +1,72 @@
+package org.apache.cassandra.stress.operations;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.math3.distribution.EnumeratedDistribution;
+import org.apache.commons.math3.util.Pair;
+
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.util.Timer;
+
+public abstract class SampledOpDistributionFactory<T> implements OpDistributionFactory
+{
+
+ final List<Pair<T, Double>> ratios;
+ final DistributionFactory clustering;
+ protected SampledOpDistributionFactory(List<Pair<T, Double>> ratios, DistributionFactory clustering)
+ {
+ this.ratios = ratios;
+ this.clustering = clustering;
+ }
+
+ protected abstract Operation get(Timer timer, PartitionGenerator generator, T key);
+ protected abstract PartitionGenerator newGenerator();
+
+ public OpDistribution get(Timer timer)
+ {
+ PartitionGenerator generator = newGenerator();
+ List<Pair<Operation, Double>> operations = new ArrayList<>();
+ for (Pair<T, Double> ratio : ratios)
+ operations.add(new Pair<>(get(timer, generator, ratio.getFirst()), ratio.getSecond()));
+ return new SampledOpDistribution(new EnumeratedDistribution<>(operations), clustering.get());
+ }
+
+ public String desc()
+ {
+ List<T> keys = new ArrayList<>();
+ for (Pair<T, Double> p : ratios)
+ keys.add(p.getFirst());
+ return keys.toString();
+ }
+
+ public Iterable<OpDistributionFactory> each()
+ {
+ List<OpDistributionFactory> out = new ArrayList<>();
+ for (final Pair<T, Double> ratio : ratios)
+ {
+ out.add(new OpDistributionFactory()
+ {
+ public OpDistribution get(Timer timer)
+ {
+ return new FixedOpDistribution(SampledOpDistributionFactory.this.get(timer, newGenerator(), ratio.getFirst()));
+ }
+
+ public String desc()
+ {
+ return ratio.getFirst().toString();
+ }
+
+ public Iterable<OpDistributionFactory> each()
+ {
+ return Collections.<OpDistributionFactory>singleton(this);
+ }
+ });
+ }
+ return out;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java
deleted file mode 100644
index 9bfe440..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterAdder.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-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;
-import org.apache.cassandra.thrift.*;
-
-public class ThriftCounterAdder extends Operation
-{
- public ThriftCounterAdder(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
- List<CounterColumn> columns = new ArrayList<>();
- for (ByteBuffer name : randomNames())
- columns.add(new CounterColumn(name, state.counteradd.next()));
-
- Map<String, List<Mutation>> row;
- if (state.settings.columns.useSuperColumns)
- {
- List<Mutation> mutations = new ArrayList<>();
- for (ColumnParent parent : state.columnParents)
- {
- CounterSuperColumn csc = new CounterSuperColumn(ByteBuffer.wrap(parent.getSuper_column()), columns);
- ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setCounter_super_column(csc);
- mutations.add(new Mutation().setColumn_or_supercolumn(cosc));
- }
- row = Collections.singletonMap(state.type.supertable, mutations);
- }
- else
- {
- List<Mutation> mutations = new ArrayList<>(columns.size());
- for (CounterColumn c : columns)
- {
- ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setCounter_column(c);
- mutations.add(new Mutation().setColumn_or_supercolumn(cosc));
- }
- row = Collections.singletonMap(state.type.table, mutations);
- }
-
- final ByteBuffer key = getKey();
- final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
-
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- client.batch_mutate(record, state.settings.command.consistencyLevel);
- return true;
- }
-
- @Override
- public String key()
- {
- return new String(key.array());
- }
-
- @Override
- public int keyCount()
- {
- return 1;
- }
- });
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java
deleted file mode 100644
index 6e36a28..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftCounterGetter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.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;
-import org.apache.cassandra.thrift.ColumnParent;
-import org.apache.cassandra.thrift.SlicePredicate;
-import org.apache.cassandra.thrift.SliceRange;
-
-public class ThriftCounterGetter extends Operation
-{
- public ThriftCounterGetter(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
- final SlicePredicate predicate = slicePredicate();
- final ByteBuffer key = getKey();
- for (final ColumnParent parent : state.columnParents)
- {
-
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- List<?> r = client.get_slice(key, parent, predicate, state.settings.command.consistencyLevel);
- return r != null && r.size() > 0;
- }
-
- @Override
- public String key()
- {
- return new String(key.array());
- }
-
- @Override
- public int keyCount()
- {
- return 1;
- }
- });
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java
deleted file mode 100644
index 8c8ec31..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftIndexedRangeSlicer.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.util.ThriftClient;
-import org.apache.cassandra.thrift.*;
-import org.apache.cassandra.utils.ByteBufferUtil;
-import org.apache.cassandra.utils.FBUtilities;
-
-public class ThriftIndexedRangeSlicer extends Operation
-{
- public ThriftIndexedRangeSlicer(State state, long index)
- {
- super(state, index);
- if (!state.rowGen.isDeterministic() || !state.keyGen.isDeterministic())
- throw new IllegalStateException("Only run with a isDeterministic row/key generator");
- if (state.settings.columns.useSuperColumns || state.columnParents.size() != 1)
- throw new IllegalStateException("Does not support super columns");
- if (state.settings.columns.useTimeUUIDComparator)
- throw new IllegalStateException("Does not support TimeUUID column names");
- }
-
- public void run(final ThriftClient client) throws IOException
- {
-
- final SlicePredicate predicate = new SlicePredicate()
- .setSlice_range(new SliceRange(ByteBufferUtil.EMPTY_BYTE_BUFFER,
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- false, state.settings.columns.maxColumnsPerKey));
- final List<ByteBuffer> columns = generateColumnValues(getKey());
- final ColumnParent parent = state.columnParents.get(0);
-
- 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);
- byte[] minKey = new byte[0];
- final List<KeySlice>[] results = new List[1];
- do
- {
-
- final boolean first = minKey.length == 0;
- final IndexClause clause = new IndexClause(Arrays.asList(expression),
- ByteBuffer.wrap(minKey),
- state.settings.command.keysAtOnce);
-
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- results[0] = client.get_indexed_slices(parent, clause, predicate, state.settings.command.consistencyLevel);
- return !first || results[0].size() > 0;
- }
-
- @Override
- public String key()
- {
- return new String(value.array());
- }
-
- @Override
- public int keyCount()
- {
- return results[0].size();
- }
- });
-
- minKey = getNextMinKey(minKey, results[0]);
-
- } while (results[0].size() > 0);
- }
-
- /**
- * Get maximum key from keySlice list
- * @param slices list of the KeySlice objects
- * @return maximum key value of the list
- */
- private static byte[] getNextMinKey(byte[] cur, List<KeySlice> slices)
- {
- // find max
- for (KeySlice slice : slices)
- if (FBUtilities.compareUnsigned(cur, slice.getKey()) < 0)
- cur = slice.getKey();
-
- // increment
- for (int i = 0 ; i < cur.length ; i++)
- if (++cur[i] != 0)
- break;
- return cur;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java
deleted file mode 100644
index 7077a95..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.stress.operations;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.cassandra.db.marshal.TimeUUIDType;
-import org.apache.cassandra.stress.Operation;
-import org.apache.cassandra.stress.util.ThriftClient;
-import org.apache.cassandra.thrift.*;
-import org.apache.cassandra.utils.FBUtilities;
-import org.apache.cassandra.utils.UUIDGen;
-
-public final class ThriftInserter extends Operation
-{
-
- public ThriftInserter(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
- final ByteBuffer key = getKey();
- final List<Column> columns = generateColumns(key);
-
- Map<String, List<Mutation>> row;
- if (!state.settings.columns.useSuperColumns)
- {
- List<Mutation> mutations = new ArrayList<>(columns.size());
- for (Column c : columns)
- {
- ColumnOrSuperColumn column = new ColumnOrSuperColumn().setColumn(c);
- mutations.add(new Mutation().setColumn_or_supercolumn(column));
- }
- row = Collections.singletonMap(state.type.table, mutations);
- }
- else
- {
- List<Mutation> mutations = new ArrayList<>(state.columnParents.size());
- for (ColumnParent parent : state.columnParents)
- {
- final SuperColumn s = new SuperColumn(parent.bufferForSuper_column(), columns);
- final ColumnOrSuperColumn cosc = new ColumnOrSuperColumn().setSuper_column(s);
- mutations.add(new Mutation().setColumn_or_supercolumn(cosc));
- }
- row = Collections.singletonMap(state.settings.command.type.supertable, mutations);
- }
-
- final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
-
- timeWithRetry(new RunOp()
- {
- @Override
- public boolean run() throws Exception
- {
- client.batch_mutate(record, state.settings.command.consistencyLevel);
- return true;
- }
-
- @Override
- public String key()
- {
- return new String(key.array());
- }
-
- @Override
- public int keyCount()
- {
- return 1;
- }
- });
- }
-
- protected List<Column> generateColumns(ByteBuffer key)
- {
- final List<ByteBuffer> values = generateColumnValues(key);
- final List<Column> columns = new ArrayList<>(values.size());
-
- if (state.settings.columns.useTimeUUIDComparator)
- for (int i = 0 ; i < values.size() ; i++)
- new Column(TimeUUIDType.instance.decompose(UUIDGen.getTimeUUID()));
- else
- // 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(state.settings.columns.names.get(i)));
-
- for (int i = 0 ; i < values.size() ; i++)
- columns.get(i)
- .setValue(values.get(i))
- .setTimestamp(FBUtilities.timestampMicros());
-
- return columns;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java b/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java
deleted file mode 100644
index d8e0117..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/operations/ThriftMultiGetter.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.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;
-import org.apache.cassandra.thrift.ColumnParent;
-import org.apache.cassandra.thrift.SlicePredicate;
-import org.apache.cassandra.thrift.SliceRange;
-import org.apache.cassandra.utils.ByteBufferUtil;
-
-
-public final class ThriftMultiGetter extends Operation
-{
-
- public ThriftMultiGetter(State state, long index)
- {
- super(state, index);
- }
-
- public void run(final ThriftClient client) throws IOException
- {
-
- final SlicePredicate predicate = new SlicePredicate().setSlice_range(
- new SliceRange(
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- ByteBufferUtil.EMPTY_BYTE_BUFFER,
- false,
- state.settings.columns.maxColumnsPerKey
- )
- );
-
- final List<ByteBuffer> keys = getKeys(state.settings.command.keysAtOnce);
-
- for (final ColumnParent parent : state.columnParents)
- {
- timeWithRetry(new RunOp()
- {
- int count;
- @Override
- public boolean run() throws Exception
- {
- return (count = client.multiget_slice(keys, parent, predicate, state.settings.command.consistencyLevel).size()) != 0;
- }
-
- @Override
- public String key()
- {
- return keys.toString();
- }
-
- @Override
- public int keyCount()
- {
- return count;
- }
- });
- }
- }
-
-}
[23/23] git commit: Merge branch 'cassandra-2.1' into trunk
Posted by be...@apache.org.
Merge branch 'cassandra-2.1' into trunk
Conflicts:
tools/stress/src/org/apache/cassandra/stress/Operation.java
tools/stress/src/org/apache/cassandra/stress/operations/CqlIndexedRangeSlicer.java
tools/stress/src/org/apache/cassandra/stress/operations/CqlRangeSlicer.java
tools/stress/src/org/apache/cassandra/stress/operations/ThriftInserter.java
tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/047c0461
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/047c0461
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/047c0461
Branch: refs/heads/trunk
Commit: 047c04611bfdbb390ae51b092c1e23e510f82135
Parents: 8f76789 35b88c5
Author: Benedict Elliott Smith <be...@apache.org>
Authored: Mon Jul 7 18:34:02 2014 +0100
Committer: Benedict Elliott Smith <be...@apache.org>
Committed: Mon Jul 7 18:34:02 2014 +0100
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../cassandra/thrift/ThriftConversion.java | 19 +
.../org/apache/cassandra/utils/UUIDGen.java | 8 +
tools/bin/cassandra-stress | 2 +-
tools/cqlstress-counter-example.yaml | 85 +++
tools/cqlstress-example.yaml | 99 +++
tools/cqlstress-insanity-example.yaml | 102 +++
.../org/apache/cassandra/stress/Operation.java | 214 +-----
.../apache/cassandra/stress/StressAction.java | 262 +++----
.../apache/cassandra/stress/StressMetrics.java | 17 +-
.../apache/cassandra/stress/StressProfile.java | 504 ++++++++++++++
.../org/apache/cassandra/stress/StressYaml.java | 38 ++
.../cassandra/stress/generate/Distribution.java | 57 ++
.../generate/DistributionBoundApache.java | 84 +++
.../stress/generate/DistributionFactory.java | 31 +
.../stress/generate/DistributionFixed.java | 54 ++
.../stress/generate/DistributionInverted.java | 37 +
.../generate/DistributionOffsetApache.java | 80 +++
.../cassandra/stress/generate/Partition.java | 343 ++++++++++
.../stress/generate/PartitionGenerator.java | 80 +++
.../stress/generate/RatioDistribution.java | 25 +
.../generate/RatioDistributionFactory.java | 31 +
.../apache/cassandra/stress/generate/Row.java | 22 +
.../stress/generate/SeedGenerator.java | 8 +
.../stress/generate/SeedRandomGenerator.java | 33 +
.../stress/generate/SeedSeriesGenerator.java | 21 +
.../stress/generate/values/Booleans.java | 37 +
.../cassandra/stress/generate/values/Bytes.java | 54 ++
.../cassandra/stress/generate/values/Dates.java | 46 ++
.../stress/generate/values/Doubles.java | 37 +
.../stress/generate/values/Floats.java | 37 +
.../stress/generate/values/Generator.java | 50 ++
.../stress/generate/values/GeneratorConfig.java | 68 ++
.../stress/generate/values/HexBytes.java | 56 ++
.../stress/generate/values/HexStrings.java | 55 ++
.../cassandra/stress/generate/values/Inets.java | 57 ++
.../stress/generate/values/Integers.java | 38 ++
.../cassandra/stress/generate/values/Lists.java | 55 ++
.../cassandra/stress/generate/values/Longs.java | 37 +
.../cassandra/stress/generate/values/Sets.java | 54 ++
.../stress/generate/values/Strings.java | 49 ++
.../stress/generate/values/TimeUUIDs.java | 51 ++
.../cassandra/stress/generate/values/UUIDs.java | 39 ++
.../cassandra/stress/generatedata/DataGen.java | 39 --
.../stress/generatedata/DataGenBytesRandom.java | 45 --
.../stress/generatedata/DataGenFactory.java | 30 -
.../stress/generatedata/DataGenHex.java | 60 --
.../DataGenHexFromDistribution.java | 66 --
.../generatedata/DataGenHexFromOpIndex.java | 48 --
.../generatedata/DataGenStringDictionary.java | 107 ---
.../generatedata/DataGenStringRepeats.java | 90 ---
.../stress/generatedata/Distribution.java | 40 --
.../generatedata/DistributionBoundApache.java | 63 --
.../generatedata/DistributionFactory.java | 31 -
.../stress/generatedata/DistributionFixed.java | 46 --
.../generatedata/DistributionOffsetApache.java | 61 --
.../generatedata/DistributionSeqBatch.java | 68 --
.../cassandra/stress/generatedata/KeyGen.java | 54 --
.../cassandra/stress/generatedata/RowGen.java | 53 --
.../generatedata/RowGenDistributedSize.java | 116 ----
.../stress/operations/CqlCounterAdder.java | 68 --
.../stress/operations/CqlCounterGetter.java | 59 --
.../operations/CqlIndexedRangeSlicer.java | 115 ----
.../stress/operations/CqlInserter.java | 87 ---
.../stress/operations/CqlMultiGetter.java | 42 --
.../stress/operations/CqlOperation.java | 658 ------------------
.../stress/operations/CqlRangeSlicer.java | 53 --
.../cassandra/stress/operations/CqlReader.java | 85 ---
.../stress/operations/FixedOpDistribution.java | 25 +
.../stress/operations/OpDistribution.java | 11 +
.../operations/OpDistributionFactory.java | 12 +
.../operations/SampledOpDistribution.java | 41 ++
.../SampledOpDistributionFactory.java | 72 ++
.../stress/operations/ThriftCounterAdder.java | 95 ---
.../stress/operations/ThriftCounterGetter.java | 68 --
.../operations/ThriftIndexedRangeSlicer.java | 114 ----
.../stress/operations/ThriftInserter.java | 119 ----
.../stress/operations/ThriftMultiGetter.java | 80 ---
.../stress/operations/ThriftRangeSlicer.java | 85 ---
.../stress/operations/ThriftReader.java | 94 ---
.../operations/predefined/CqlCounterAdder.java | 78 +++
.../operations/predefined/CqlCounterGetter.java | 59 ++
.../operations/predefined/CqlInserter.java | 78 +++
.../operations/predefined/CqlOperation.java | 674 +++++++++++++++++++
.../stress/operations/predefined/CqlReader.java | 81 +++
.../predefined/PredefinedOperation.java | 244 +++++++
.../predefined/ThriftCounterAdder.java | 86 +++
.../predefined/ThriftCounterGetter.java | 66 ++
.../operations/predefined/ThriftInserter.java | 98 +++
.../operations/predefined/ThriftReader.java | 79 +++
.../operations/userdefined/SchemaInsert.java | 144 ++++
.../operations/userdefined/SchemaQuery.java | 86 +++
.../operations/userdefined/SchemaStatement.java | 164 +++++
.../cassandra/stress/settings/Command.java | 24 +-
.../stress/settings/CommandCategory.java | 4 +-
.../stress/settings/OptionAnyProbabilities.java | 78 +++
.../stress/settings/OptionDataGen.java | 203 ------
.../stress/settings/OptionDistribution.java | 75 ++-
.../settings/OptionEnumProbabilities.java | 62 ++
.../cassandra/stress/settings/OptionMulti.java | 3 +-
.../settings/OptionRatioDistribution.java | 166 +++++
.../cassandra/stress/settings/OptionSimple.java | 5 +-
.../stress/settings/SettingsColumn.java | 50 +-
.../stress/settings/SettingsCommand.java | 58 +-
.../stress/settings/SettingsCommandMixed.java | 207 ------
.../settings/SettingsCommandPreDefined.java | 145 ++++
.../SettingsCommandPreDefinedMixed.java | 151 +++++
.../stress/settings/SettingsCommandUser.java | 135 ++++
.../cassandra/stress/settings/SettingsKey.java | 27 +-
.../cassandra/stress/settings/SettingsMisc.java | 2 +-
.../cassandra/stress/settings/SettingsMode.java | 6 +-
.../stress/settings/SettingsSchema.java | 77 +--
.../stress/settings/SettingsTransport.java | 2 +-
.../stress/settings/StressSettings.java | 36 +-
.../stress/settings/ValidationType.java | 8 +
.../cassandra/stress/util/JavaDriverClient.java | 19 +-
.../stress/util/SmartThriftClient.java | 4 +-
.../org/apache/cassandra/stress/util/Timer.java | 17 +-
.../cassandra/stress/util/TimingInterval.java | 26 +-
119 files changed, 5791 insertions(+), 3813 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/047c0461/CHANGES.txt
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/047c0461/src/java/org/apache/cassandra/utils/UUIDGen.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/047c0461/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
----------------------------------------------------------------------
diff --cc tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
index 0000000,f794e75..2263e45
mode 000000,100644..100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterAdder.java
@@@ -1,0 -1,84 +1,78 @@@
+ package org.apache.cassandra.stress.operations.predefined;
+ /*
+ *
+ * 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.
+ *
+ */
+
+
+ import java.nio.ByteBuffer;
+ import java.util.ArrayList;
+ import java.util.List;
+
+ import org.apache.cassandra.stress.generate.Distribution;
+ import org.apache.cassandra.stress.generate.DistributionFactory;
+ import org.apache.cassandra.stress.generate.PartitionGenerator;
+ import org.apache.cassandra.stress.settings.Command;
+ import org.apache.cassandra.stress.settings.StressSettings;
+ import org.apache.cassandra.stress.util.Timer;
+
+ public class CqlCounterAdder extends CqlOperation<Integer>
+ {
+
+ final Distribution counteradd;
+ public CqlCounterAdder(DistributionFactory counteradd, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_WRITE, timer, generator, settings);
+ this.counteradd = counteradd.get();
+ }
+
+ @Override
+ protected String buildQuery()
+ {
- String counterCF = isCql2() ? type.table : "Counter3";
-
- StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(counterCF));
-
- if (isCql2())
- query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
-
- query.append(" SET ");
++ StringBuilder query = new StringBuilder("UPDATE \"Counter3\" SET ");
+
+ // TODO : increment distribution subset of columns
+ for (int i = 0; i < settings.columns.maxColumnsPerKey; i++)
+ {
+ if (i > 0)
+ query.append(",");
+
- query.append('C').append(i).append("=C").append(i).append("+?");
++ String name = settings.columns.namestrs.get(i);
++ query.append(name).append("=").append(name).append("+?");
+ }
+ query.append(" WHERE KEY=?");
+ return query.toString();
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ final List<Object> list = new ArrayList<>();
+ for (int i = 0; i < settings.columns.maxColumnsPerKey; i++)
+ list.add(counteradd.next());
+ list.add(ByteBuffer.wrap(key));
+ return list;
+ }
+
+ @Override
+ protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ return new CqlRunOpAlwaysSucceed(client, query, queryId, params, key, 1);
+ }
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/047c0461/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
----------------------------------------------------------------------
diff --cc tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
index 0000000,94c8faf..63f12c5
mode 000000,100644..100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlCounterGetter.java
@@@ -1,0 -1,74 +1,59 @@@
+ package org.apache.cassandra.stress.operations.predefined;
+ /*
+ *
+ * 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.
+ *
+ */
+
+
+ import java.nio.ByteBuffer;
+ import java.util.Collections;
+ import java.util.List;
+
+ import org.apache.cassandra.stress.generate.PartitionGenerator;
+ import org.apache.cassandra.stress.settings.Command;
+ import org.apache.cassandra.stress.settings.StressSettings;
+ import org.apache.cassandra.stress.util.Timer;
+
+ public class CqlCounterGetter extends CqlOperation<Integer>
+ {
+
+ public CqlCounterGetter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.COUNTER_READ, timer, generator, settings);
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ return Collections.<Object>singletonList(ByteBuffer.wrap(key));
+ }
+
+ @Override
+ protected String buildQuery()
+ {
- StringBuilder query = new StringBuilder("SELECT ");
-
- // TODO: obey slice/noslice option (instead of always slicing)
- if (isCql2())
- query.append("FIRST ").append(settings.columns.maxColumnsPerKey).append(" ''..''");
- else
- query.append("*");
-
- String counterCF = isCql2() ? type.table : "Counter3";
-
- query.append(" FROM ").append(wrapInQuotesIfRequired(counterCF));
-
- if (isCql2())
- query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
-
- return query.append(" WHERE KEY=?").toString();
++ return "SELECT * FROM " + wrapInQuotes(type.table) + " WHERE KEY=?";
+ }
+
+ @Override
+ protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ return new CqlRunOpTestNonEmpty(client, query, queryId, params, key);
+ }
+
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/047c0461/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
----------------------------------------------------------------------
diff --cc tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
index 0000000,c422f2b..fc95b40
mode 000000,100644..100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlInserter.java
@@@ -1,0 -1,79 +1,78 @@@
+ package org.apache.cassandra.stress.operations.predefined;
+ /*
+ *
+ * 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.
+ *
+ */
+
+
+ import java.nio.ByteBuffer;
+ import java.util.ArrayList;
+ import java.util.List;
+
+ import org.apache.cassandra.stress.generate.PartitionGenerator;
+ import org.apache.cassandra.stress.settings.Command;
+ import org.apache.cassandra.stress.settings.StressSettings;
+ import org.apache.cassandra.stress.util.Timer;
+ import org.apache.cassandra.utils.UUIDGen;
+
+ public class CqlInserter extends CqlOperation<Integer>
+ {
+
+ public CqlInserter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.WRITE, timer, generator, settings);
+ }
+
+ @Override
+ protected String buildQuery()
+ {
- StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotesIfRequired(type.table));
-
- if (isCql2())
- query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
++ StringBuilder query = new StringBuilder("UPDATE ").append(wrapInQuotes(type.table));
++ if (settings.columns.timestamp != null)
++ query.append(" USING TIMESTAMP ").append(settings.columns.timestamp);
+
+ query.append(" SET ");
+
+ for (int i = 0 ; i < settings.columns.maxColumnsPerKey ; i++)
+ {
+ if (i > 0)
+ query.append(',');
+
- query.append(wrapInQuotesIfRequired(settings.columns.namestrs.get(i))).append(" = ?");
++ query.append(wrapInQuotes(settings.columns.namestrs.get(i))).append(" = ?");
+ }
+
+ query.append(" WHERE KEY=?");
+ return query.toString();
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ final ArrayList<Object> queryParams = new ArrayList<>();
+ List<ByteBuffer> values = getColumnValues();
+ queryParams.addAll(values);
+ queryParams.add(ByteBuffer.wrap(key));
+ return queryParams;
+ }
+
+ @Override
+ protected CqlRunOp<Integer> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ return new CqlRunOpAlwaysSucceed(client, query, queryId, params, key, 1);
+ }
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/047c0461/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
----------------------------------------------------------------------
diff --cc tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
index 0000000,0264cd1..318555e
mode 000000,100644..100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlOperation.java
@@@ -1,0 -1,714 +1,674 @@@
+ /*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ package org.apache.cassandra.stress.operations.predefined;
+
+ import java.io.IOException;
+ import java.nio.ByteBuffer;
+ import java.util.ArrayList;
+ import java.util.Arrays;
+ import java.util.List;
+
+ import com.datastax.driver.core.PreparedStatement;
+ import com.datastax.driver.core.ResultSet;
+ import com.datastax.driver.core.Row;
+ import com.google.common.base.Function;
+ import org.apache.cassandra.stress.Operation;
+ import org.apache.cassandra.stress.StressMetrics;
+ import org.apache.cassandra.stress.generate.PartitionGenerator;
+ import org.apache.cassandra.stress.settings.Command;
+ import org.apache.cassandra.stress.settings.ConnectionStyle;
+ import org.apache.cassandra.stress.settings.CqlVersion;
+ import org.apache.cassandra.stress.settings.StressSettings;
+ import org.apache.cassandra.stress.util.JavaDriverClient;
+ import org.apache.cassandra.stress.util.ThriftClient;
+ import org.apache.cassandra.stress.util.Timer;
+ import org.apache.cassandra.thrift.Compression;
+ import org.apache.cassandra.thrift.CqlResult;
+ import org.apache.cassandra.thrift.CqlRow;
+ import org.apache.cassandra.thrift.ThriftConversion;
+ import org.apache.cassandra.transport.SimpleClient;
+ import org.apache.cassandra.transport.messages.ResultMessage;
+ import org.apache.cassandra.utils.ByteBufferUtil;
+ import org.apache.thrift.TException;
+
+ public abstract class CqlOperation<V> extends PredefinedOperation
+ {
+
+ protected abstract List<Object> getQueryParameters(byte[] key);
+ protected abstract String buildQuery();
+ protected abstract CqlRunOp<V> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key);
+
+ public CqlOperation(Command type, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(type, timer, generator, settings);
+ if (settings.columns.variableColumnCount)
+ throw new IllegalStateException("Variable column counts are not implemented for CQL");
+ }
+
+ protected CqlRunOp<V> run(final ClientWrapper client, final List<Object> queryParams, final ByteBuffer key) throws IOException
+ {
+ final CqlRunOp<V> op;
+ if (settings.mode.style == ConnectionStyle.CQL_PREPARED)
+ {
+ final Object id;
+ Object idobj = getCqlCache();
+ if (idobj == null)
+ {
+ try
+ {
+ id = client.createPreparedStatement(buildQuery());
+ } catch (TException e)
+ {
+ throw new RuntimeException(e);
+ }
+ storeCqlCache(id);
+ }
+ else
+ id = idobj;
+
+ op = buildRunOp(client, null, id, queryParams, key);
+ }
+ else
+ {
+ final String query;
+ Object qobj = getCqlCache();
+ if (qobj == null)
+ storeCqlCache(query = buildQuery());
+ else
+ query = qobj.toString();
+
+ op = buildRunOp(client, query, null, queryParams, key);
+ }
+
+ timeWithRetry(op);
+ return op;
+ }
+
+ protected void run(final ClientWrapper client) throws IOException
+ {
+ final byte[] key = getKey().array();
+ final List<Object> queryParams = getQueryParameters(key);
+ run(client, queryParams, ByteBuffer.wrap(key));
+ }
+
+ // Classes to process Cql results
+
+ // Always succeeds so long as the query executes without error; provides a keyCount to increment on instantiation
+ protected final class CqlRunOpAlwaysSucceed extends CqlRunOp<Integer>
+ {
+
+ final int keyCount;
+
+ protected CqlRunOpAlwaysSucceed(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key, int keyCount)
+ {
+ super(client, query, queryId, RowCountHandler.INSTANCE, params, key);
+ this.keyCount = keyCount;
+ }
+
+ @Override
+ public boolean validate(Integer result)
+ {
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return keyCount;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return keyCount;
+ }
+ }
+
+ // Succeeds so long as the result set is nonempty, and the query executes without error
+ protected final class CqlRunOpTestNonEmpty extends CqlRunOp<Integer>
+ {
+
+ protected CqlRunOpTestNonEmpty(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ super(client, query, queryId, RowCountHandler.INSTANCE, params, key);
+ }
+
+ @Override
+ public boolean validate(Integer result)
+ {
+ return result > 0;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return result;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return result;
+ }
+ }
+
+ // Requires a custom validate() method, but fetches and stores the keys from the result set for further processing
+ protected abstract class CqlRunOpFetchKeys extends CqlRunOp<byte[][]>
+ {
+
+ protected CqlRunOpFetchKeys(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ super(client, query, queryId, KeysHandler.INSTANCE, params, key);
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return result.length;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return result.length;
+ }
+ }
+
+ protected final class CqlRunOpMatchResults extends CqlRunOp<ByteBuffer[][]>
+ {
+
+ final List<List<ByteBuffer>> 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<Object> params, ByteBuffer key, List<List<ByteBuffer>> expect)
+ {
+ super(client, query, queryId, RowsHandler.INSTANCE, params, key);
+ this.expect = expect;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return result == null ? 0 : result.length;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return result == null ? 0 : result.length;
+ }
+
+ public boolean validate(ByteBuffer[][] result)
+ {
+ if (result.length != expect.size())
+ return false;
+ for (int i = 0 ; i < result.length ; i++)
+ if (expect.get(i) != null && !expect.get(i).equals(Arrays.asList(result[i])))
+ return false;
+ return true;
+ }
+ }
+
+ // Cql
+ protected abstract class CqlRunOp<V> implements RunOp
+ {
+
+ final ClientWrapper client;
+ final String query;
+ final Object queryId;
+ final List<Object> params;
+ final ByteBuffer key;
+ final ResultHandler<V> handler;
+ V result;
+
+ private CqlRunOp(ClientWrapper client, String query, Object queryId, ResultHandler<V> handler, List<Object> params, ByteBuffer key)
+ {
+ this.client = client;
+ this.query = query;
+ this.queryId = queryId;
+ this.handler = handler;
+ this.params = params;
+ this.key = key;
+ }
+
+ @Override
+ public boolean run() throws Exception
+ {
+ return queryId != null
+ ? validate(result = client.execute(queryId, key, params, handler))
+ : validate(result = client.execute(query, key, params, handler));
+ }
+
+ public abstract boolean validate(V result);
+
+ }
+
+
+ /// LOTS OF WRAPPING/UNWRAPPING NONSENSE
+
+
+ @Override
+ public void run(final ThriftClient client) throws IOException
+ {
+ run(wrap(client));
+ }
+
+ @Override
+ public void run(SimpleClient client) throws IOException
+ {
+ run(wrap(client));
+ }
+
+ @Override
+ public void run(JavaDriverClient client) throws IOException
+ {
+ run(wrap(client));
+ }
+
+ public ClientWrapper wrap(ThriftClient client)
+ {
- return isCql3()
- ? new Cql3CassandraClientWrapper(client)
- : new Cql2CassandraClientWrapper(client);
-
++ return new Cql3CassandraClientWrapper(client);
+ }
+
+ public ClientWrapper wrap(JavaDriverClient client)
+ {
+ return new JavaDriverWrapper(client);
+ }
+
+ public ClientWrapper wrap(SimpleClient client)
+ {
+ return new SimpleClientWrapper(client);
+ }
+
+ protected interface ClientWrapper
+ {
+ Object createPreparedStatement(String cqlQuery) throws TException;
+ <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
+ <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException;
+ }
+
+ private final class JavaDriverWrapper implements ClientWrapper
+ {
+ final JavaDriverClient client;
+ private JavaDriverWrapper(JavaDriverClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
- String formattedQuery = formatCqlQuery(query, queryParams, isCql3());
++ String formattedQuery = formatCqlQuery(query, queryParams);
+ return handler.javaDriverHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ return handler.javaDriverHandler().apply(
+ client.executePrepared(
+ (PreparedStatement) preparedStatementId,
+ queryParams,
+ ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery)
+ {
+ return client.prepare(cqlQuery);
+ }
+ }
+
+ private final class SimpleClientWrapper implements ClientWrapper
+ {
+ final SimpleClient client;
+ private SimpleClientWrapper(SimpleClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
- String formattedQuery = formatCqlQuery(query, queryParams, isCql3());
++ String formattedQuery = formatCqlQuery(query, queryParams);
+ return handler.thriftHandler().apply(client.execute(formattedQuery, ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler)
+ {
+ return handler.thriftHandler().apply(
+ client.executePrepared(
+ (byte[]) preparedStatementId,
+ toByteBufferParams(queryParams),
+ ThriftConversion.fromThrift(settings.command.consistencyLevel)));
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery)
+ {
+ return client.prepare(cqlQuery).statementId.bytes;
+ }
+ }
+
+ // client wrapper for Cql3
+ private final class Cql3CassandraClientWrapper implements ClientWrapper
+ {
+ final ThriftClient client;
+ private Cql3CassandraClientWrapper(ThriftClient client)
+ {
+ this.client = client;
+ }
+
+ @Override
+ public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
- String formattedQuery = formatCqlQuery(query, queryParams, true);
++ String formattedQuery = formatCqlQuery(query, queryParams);
+ return handler.simpleNativeHandler().apply(
+ client.execute_cql3_query(formattedQuery, key, Compression.NONE, settings.command.consistencyLevel)
+ );
+ }
+
+ @Override
+ public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
+ {
+ Integer id = (Integer) preparedStatementId;
+ return handler.simpleNativeHandler().apply(
+ client.execute_prepared_cql3_query(id, key, toByteBufferParams(queryParams), settings.command.consistencyLevel)
+ );
+ }
+
+ @Override
+ public Object createPreparedStatement(String cqlQuery) throws TException
+ {
+ return client.prepare_cql3_query(cqlQuery, Compression.NONE);
+ }
+ }
+
- // client wrapper for Cql2
- private final class Cql2CassandraClientWrapper implements ClientWrapper
- {
- final ThriftClient client;
- private Cql2CassandraClientWrapper(ThriftClient client)
- {
- this.client = client;
- }
-
- @Override
- public <V> V execute(String query, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- String formattedQuery = formatCqlQuery(query, queryParams, false);
- return handler.simpleNativeHandler().apply(
- client.execute_cql_query(formattedQuery, key, Compression.NONE)
- );
- }
-
- @Override
- public <V> V execute(Object preparedStatementId, ByteBuffer key, List<Object> queryParams, ResultHandler<V> handler) throws TException
- {
- Integer id = (Integer) preparedStatementId;
- return handler.simpleNativeHandler().apply(
- client.execute_prepared_cql_query(id, key, toByteBufferParams(queryParams))
- );
- }
-
- @Override
- public Object createPreparedStatement(String cqlQuery) throws TException
- {
- return client.prepare_cql_query(cqlQuery, Compression.NONE);
- }
- }
-
+ // interface for building functions to standardise results from each client
+ protected static interface ResultHandler<V>
+ {
+ Function<ResultSet, V> javaDriverHandler();
+ Function<ResultMessage, V> thriftHandler();
+ Function<CqlResult, V> simpleNativeHandler();
+ }
+
+ protected static class RowCountHandler implements ResultHandler<Integer>
+ {
+ static final RowCountHandler INSTANCE = new RowCountHandler();
+
+ @Override
+ public Function<ResultSet, Integer> javaDriverHandler()
+ {
+ return new Function<ResultSet, Integer>()
+ {
+ @Override
+ public Integer apply(ResultSet rows)
+ {
+ if (rows == null)
+ return 0;
+ return rows.all().size();
+ }
+ };
+ }
+
+ @Override
+ public Function<ResultMessage, Integer> thriftHandler()
+ {
+ return new Function<ResultMessage, Integer>()
+ {
+ @Override
+ public Integer apply(ResultMessage result)
+ {
+ return result instanceof ResultMessage.Rows ? ((ResultMessage.Rows) result).result.size() : 0;
+ }
+ };
+ }
+
+ @Override
+ public Function<CqlResult, Integer> simpleNativeHandler()
+ {
+ return new Function<CqlResult, Integer>()
+ {
+
+ @Override
+ public Integer apply(CqlResult result)
+ {
+ switch (result.getType())
+ {
+ case ROWS:
+ return result.getRows().size();
+ default:
+ return 1;
+ }
+ }
+ };
+ }
+
+ }
+
+ // Processes results from each client into an array of all key bytes returned
+ protected static final class RowsHandler implements ResultHandler<ByteBuffer[][]>
+ {
+ static final RowsHandler INSTANCE = new RowsHandler();
+
+ @Override
+ public Function<ResultSet, ByteBuffer[][]> javaDriverHandler()
+ {
+ return new Function<ResultSet, ByteBuffer[][]>()
+ {
+
+ @Override
+ public ByteBuffer[][] apply(ResultSet result)
+ {
+ if (result == null)
+ return new ByteBuffer[0][];
+ List<Row> rows = result.all();
+
+ ByteBuffer[][] r = new ByteBuffer[rows.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ {
+ Row row = rows.get(i);
+ r[i] = new ByteBuffer[row.getColumnDefinitions().size()];
+ for (int j = 0 ; j < row.getColumnDefinitions().size() ; j++)
+ r[i][j] = row.getBytes(j);
+ }
+ return r;
+ }
+ };
+ }
+
+ @Override
+ public Function<ResultMessage, ByteBuffer[][]> thriftHandler()
+ {
+ return new Function<ResultMessage, ByteBuffer[][]>()
+ {
+
+ @Override
+ public ByteBuffer[][] apply(ResultMessage result)
+ {
+ if (!(result instanceof ResultMessage.Rows))
+ return new ByteBuffer[0][];
+
+ ResultMessage.Rows rows = ((ResultMessage.Rows) result);
+ ByteBuffer[][] r = new ByteBuffer[rows.result.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ {
+ List<ByteBuffer> row = rows.result.rows.get(i);
+ r[i] = new ByteBuffer[row.size()];
+ for (int j = 0 ; j < row.size() ; j++)
+ r[i][j] = row.get(j);
+ }
+ return r;
+ }
+ };
+ }
+
+ @Override
+ public Function<CqlResult, ByteBuffer[][]> simpleNativeHandler()
+ {
+ return new Function<CqlResult, ByteBuffer[][]>()
+ {
+
+ @Override
+ public ByteBuffer[][] apply(CqlResult result)
+ {
+ ByteBuffer[][] r = new ByteBuffer[result.getRows().size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ {
+ CqlRow row = result.getRows().get(i);
+ r[i] = new ByteBuffer[row.getColumns().size()];
+ for (int j = 0 ; j < r[i].length ; j++)
+ r[i][j] = ByteBuffer.wrap(row.getColumns().get(j).getValue());
+ }
+ return r;
+ }
+ };
+ }
+
+ }
+ // Processes results from each client into an array of all key bytes returned
+ protected static final class KeysHandler implements ResultHandler<byte[][]>
+ {
+ static final KeysHandler INSTANCE = new KeysHandler();
+
+ @Override
+ public Function<ResultSet, byte[][]> javaDriverHandler()
+ {
+ return new Function<ResultSet, byte[][]>()
+ {
+
+ @Override
+ public byte[][] apply(ResultSet result)
+ {
+
+ if (result == null)
+ return new byte[0][];
+ List<Row> rows = result.all();
+ byte[][] r = new byte[rows.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ r[i] = rows.get(i).getBytes(0).array();
+ return r;
+ }
+ };
+ }
+
+ @Override
+ public Function<ResultMessage, byte[][]> thriftHandler()
+ {
+ return new Function<ResultMessage, byte[][]>()
+ {
+
+ @Override
+ public byte[][] apply(ResultMessage result)
+ {
+ if (result instanceof ResultMessage.Rows)
+ {
+ ResultMessage.Rows rows = ((ResultMessage.Rows) result);
+ byte[][] r = new byte[rows.result.size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ r[i] = rows.result.rows.get(i).get(0).array();
+ return r;
+ }
+ return null;
+ }
+ };
+ }
+
+ @Override
+ public Function<CqlResult, byte[][]> simpleNativeHandler()
+ {
+ return new Function<CqlResult, byte[][]>()
+ {
+
+ @Override
+ public byte[][] apply(CqlResult result)
+ {
+ byte[][] r = new byte[result.getRows().size()][];
+ for (int i = 0 ; i < r.length ; i++)
+ r[i] = result.getRows().get(i).getKey();
+ return r;
+ }
+ };
+ }
+
+ }
+
- private static String getUnQuotedCqlBlob(ByteBuffer term, boolean isCQL3)
++ private static String getUnQuotedCqlBlob(ByteBuffer term)
+ {
- return isCQL3
- ? "0x" + ByteBufferUtil.bytesToHex(term)
- : ByteBufferUtil.bytesToHex(term);
++ return "0x" + ByteBufferUtil.bytesToHex(term);
+ }
+
+ /**
+ * Constructs a CQL query string by replacing instances of the character
+ * '?', with the corresponding parameter.
+ *
+ * @param query base query string to format
+ * @param parms sequence of string query parameters
+ * @return formatted CQL query string
+ */
- private static String formatCqlQuery(String query, List<Object> parms, boolean isCql3)
++ private static String formatCqlQuery(String query, List<Object> parms)
+ {
+ int marker, position = 0;
+ StringBuilder result = new StringBuilder();
+
+ if (-1 == (marker = query.indexOf('?')) || parms.size() == 0)
+ return query;
+
+ for (Object parm : parms)
+ {
+ result.append(query.substring(position, marker));
++
+ if (parm instanceof ByteBuffer)
- result.append(getUnQuotedCqlBlob((ByteBuffer) parm, isCql3));
++ result.append(getUnQuotedCqlBlob((ByteBuffer) parm));
+ else if (parm instanceof Long)
+ result.append(parm.toString());
+ else throw new AssertionError();
+
+ position = marker + 1;
+ if (-1 == (marker = query.indexOf('?', position + 1)))
+ break;
+ }
+
+ if (position < query.length())
+ result.append(query.substring(position));
+
+ return result.toString();
+ }
+
+ private static List<ByteBuffer> toByteBufferParams(List<Object> params)
+ {
+ List<ByteBuffer> 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)
++ protected String wrapInQuotes(String string)
+ {
- return settings.mode.cqlVersion == CqlVersion.CQL3
- ? "\"" + string + "\""
- : string;
++ return "\"" + string + "\"";
+ }
+
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/047c0461/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
----------------------------------------------------------------------
diff --cc tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
index 0000000,3a7f75a..b06d866
mode 000000,100644..100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/CqlReader.java
@@@ -1,0 -1,87 +1,81 @@@
+ package org.apache.cassandra.stress.operations.predefined;
+ /*
+ *
+ * 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.
+ *
+ */
+
+
+ import java.nio.ByteBuffer;
+ import java.nio.charset.CharacterCodingException;
+ import java.util.Arrays;
+ import java.util.Collections;
+ import java.util.List;
+
+ import org.apache.cassandra.stress.generate.PartitionGenerator;
+ import org.apache.cassandra.stress.settings.Command;
+ import org.apache.cassandra.stress.settings.StressSettings;
+ import org.apache.cassandra.stress.util.Timer;
+ import org.apache.cassandra.utils.ByteBufferUtil;
+
+ public class CqlReader extends CqlOperation<ByteBuffer[][]>
+ {
+
+ public CqlReader(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.READ, timer, generator, settings);
+ }
+
+ @Override
+ protected String buildQuery()
+ {
+ StringBuilder query = new StringBuilder("SELECT ");
+
+ if (settings.columns.slice)
+ {
- if (isCql2())
- query.append("FIRST ").append(settings.columns.maxColumnsPerKey).append(" ''..''");
- else
- query.append("*");
++ query.append("*");
+ }
+ else
+ {
+ for (int i = 0; i < settings.columns.maxColumnsPerKey ; i++)
+ {
+ if (i > 0)
+ query.append(",");
- query.append(wrapInQuotesIfRequired(settings.columns.namestrs.get(i)));
++ query.append(wrapInQuotes(settings.columns.namestrs.get(i)));
+ }
+ }
+
- query.append(" FROM ").append(wrapInQuotesIfRequired(type.table));
-
- if (isCql2())
- query.append(" USING CONSISTENCY ").append(settings.command.consistencyLevel);
++ query.append(" FROM ").append(wrapInQuotes(type.table));
+ query.append(" WHERE KEY=?");
+ return query.toString();
+ }
+
+ @Override
+ protected List<Object> getQueryParameters(byte[] key)
+ {
+ return Collections.<Object>singletonList(ByteBuffer.wrap(key));
+ }
+
+ @Override
+ protected CqlRunOp<ByteBuffer[][]> buildRunOp(ClientWrapper client, String query, Object queryId, List<Object> params, ByteBuffer key)
+ {
+ List<ByteBuffer> expectRow = getColumnValues();
+ return new CqlRunOpMatchResults(client, query, queryId, params, key, Arrays.asList(expectRow));
+ }
+
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/047c0461/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
----------------------------------------------------------------------
diff --cc tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
index 0000000,7f6412b..06bcfd6
mode 000000,100644..100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/PredefinedOperation.java
@@@ -1,0 -1,248 +1,244 @@@
+ /**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ package org.apache.cassandra.stress.operations.predefined;
+
+ 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.Operation;
+ import org.apache.cassandra.stress.StressMetrics;
+ import org.apache.cassandra.stress.generate.Distribution;
+ import org.apache.cassandra.stress.generate.DistributionFactory;
+ import org.apache.cassandra.stress.generate.DistributionFixed;
+ import org.apache.cassandra.stress.generate.PartitionGenerator;
+ import org.apache.cassandra.stress.generate.Row;
+ import org.apache.cassandra.stress.settings.Command;
+ import org.apache.cassandra.stress.settings.CqlVersion;
+ import org.apache.cassandra.stress.settings.StressSettings;
+ import org.apache.cassandra.stress.util.Timer;
+ import org.apache.cassandra.thrift.ColumnParent;
+ import org.apache.cassandra.thrift.SlicePredicate;
+ import org.apache.cassandra.thrift.SliceRange;
+ import org.apache.cassandra.utils.ByteBufferUtil;
+
+ public abstract class PredefinedOperation extends Operation
+ {
+ public final Command type;
+ private final Distribution columnCount;
+ private Object cqlCache;
+
+ public PredefinedOperation(Command type, Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(timer, generator, settings, new DistributionFixed(1));
+ this.type = type;
+ this.columnCount = settings.columns.countDistribution.get();
+ }
+
+ public boolean isCql3()
+ {
+ return settings.mode.cqlVersion == CqlVersion.CQL3;
+ }
- public boolean isCql2()
- {
- return settings.mode.cqlVersion == CqlVersion.CQL2;
- }
+ public Object getCqlCache()
+ {
+ return cqlCache;
+ }
+ public void storeCqlCache(Object val)
+ {
+ cqlCache = val;
+ }
+
+ protected ByteBuffer getKey()
+ {
+ return (ByteBuffer) partitions.get(0).getPartitionKey(0);
+ }
+
+ final class ColumnSelection
+ {
+ final int[] indices;
+ final int lb, ub;
+ private ColumnSelection(int[] indices, int lb, int ub)
+ {
+ this.indices = indices;
+ this.lb = lb;
+ this.ub = ub;
+ }
+
+ public <V> List<V> select(List<V> in)
+ {
+ List<V> out = new ArrayList<>();
+ if (indices != null)
+ {
+ for (int i : indices)
+ out.add(in.get(i));
+ }
+ else
+ {
+ out.addAll(in.subList(lb, ub));
+ }
+ return out;
+ }
+
+ int count()
+ {
+ return indices != null ? indices.length : ub - lb;
+ }
+
+ SlicePredicate predicate()
+ {
+ final SlicePredicate predicate = new SlicePredicate();
+ if (indices == null)
+ {
+ predicate.setSlice_range(new SliceRange()
+ .setStart(settings.columns.names.get(lb))
+ .setFinish(new byte[] {})
+ .setReversed(false)
+ .setCount(count())
+ );
+ }
+ else
+ predicate.setColumn_names(select(settings.columns.names));
+ return predicate;
+
+ }
+ }
+
+ public String toString()
+ {
+ return type.toString();
+ }
+
+ ColumnSelection select()
+ {
+ if (settings.columns.slice)
+ {
+ int count = (int) columnCount.next();
+ int start;
+ if (count == settings.columns.maxColumnsPerKey)
+ start = 0;
+ else
+ start = 1 + ThreadLocalRandom.current().nextInt(settings.columns.maxColumnsPerKey - count);
+ return new ColumnSelection(null, start, start + count);
+ }
+
+ int count = (int) columnCount.next();
+ int totalCount = settings.columns.names.size();
+ if (count == settings.columns.names.size())
+ return new ColumnSelection(null, 0, count);
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ int[] indices = new int[count];
+ int c = 0, o = 0;
+ while (c < count && count + o < totalCount)
+ {
+ int leeway = totalCount - (count + o);
+ int spreadover = count - c;
+ o += Math.round(rnd.nextDouble() * (leeway / (double) spreadover));
+ indices[c] = o + c;
+ c++;
+ }
+ while (c < count)
+ {
+ indices[c] = o + c;
+ c++;
+ }
+ return new ColumnSelection(indices, 0, 0);
+ }
+
+ protected List<ByteBuffer> getColumnValues()
+ {
+ return getColumnValues(new ColumnSelection(null, 0, settings.columns.names.size()));
+ }
+
+ protected List<ByteBuffer> getColumnValues(ColumnSelection columns)
+ {
+ Row row = partitions.get(0).iterator(1).batch(1f).iterator().next();
+ ByteBuffer[] r = new ByteBuffer[columns.count()];
+ int c = 0;
+ if (columns.indices != null)
+ for (int i : columns.indices)
+ r[c++] = (ByteBuffer) row.get(i);
+ else
+ for (int i = columns.lb ; i < columns.ub ; i++)
+ r[c++] = (ByteBuffer) row.get(i);
+ return Arrays.asList(r);
+ }
+
+ public static Operation operation(Command type, Timer timer, PartitionGenerator generator, StressSettings settings, DistributionFactory counteradd)
+ {
+ switch (type)
+ {
+ case READ:
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftReader(timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlReader(timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+
+ case COUNTER_READ:
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftCounterGetter(timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlCounterGetter(timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ case WRITE:
+
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftInserter(timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlInserter(timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ case COUNTER_WRITE:
+ switch(settings.mode.style)
+ {
+ case THRIFT:
+ return new ThriftCounterAdder(counteradd, timer, generator, settings);
+ case CQL:
+ case CQL_PREPARED:
+ return new CqlCounterAdder(counteradd, timer, generator, settings);
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ throw new UnsupportedOperationException();
+ }
+
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/047c0461/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
----------------------------------------------------------------------
diff --cc tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
index 0000000,5c2acfe..e71f3f5
mode 000000,100644..100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/predefined/ThriftInserter.java
@@@ -1,0 -1,96 +1,98 @@@
+ /**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ package org.apache.cassandra.stress.operations.predefined;
+
+ import java.io.IOException;
+ import java.nio.ByteBuffer;
+ import java.util.ArrayList;
+ import java.util.Collections;
+ import java.util.List;
+ import java.util.Map;
+
+ import org.apache.cassandra.db.marshal.TimeUUIDType;
+ import org.apache.cassandra.stress.generate.PartitionGenerator;
+ import org.apache.cassandra.stress.settings.Command;
+ import org.apache.cassandra.stress.settings.StressSettings;
+ import org.apache.cassandra.stress.util.ThriftClient;
+ import org.apache.cassandra.stress.util.Timer;
+ import org.apache.cassandra.thrift.*;
+ import org.apache.cassandra.utils.FBUtilities;
+ import org.apache.cassandra.utils.UUIDGen;
+
+ public final class ThriftInserter extends PredefinedOperation
+ {
+
+ public ThriftInserter(Timer timer, PartitionGenerator generator, StressSettings settings)
+ {
+ super(Command.WRITE, timer, generator, settings);
+ }
+
+ public void run(final ThriftClient client) throws IOException
+ {
+ final ByteBuffer key = getKey();
+ final List<Column> columns = getColumns();
+
+ List<Mutation> mutations = new ArrayList<>(columns.size());
+ for (Column c : columns)
+ {
+ ColumnOrSuperColumn column = new ColumnOrSuperColumn().setColumn(c);
+ mutations.add(new Mutation().setColumn_or_supercolumn(column));
+ }
+ Map<String, List<Mutation>> row = Collections.singletonMap(type.table, mutations);
+
+ final Map<ByteBuffer, Map<String, List<Mutation>>> record = Collections.singletonMap(key, row);
+
+ timeWithRetry(new RunOp()
+ {
+ @Override
+ public boolean run() throws Exception
+ {
+ client.batch_mutate(record, settings.command.consistencyLevel);
+ return true;
+ }
+
+ @Override
+ public int partitionCount()
+ {
+ return 1;
+ }
+
+ @Override
+ public int rowCount()
+ {
+ return 1;
+ }
+ });
+ }
+
+ protected List<Column> getColumns()
+ {
+ final ColumnSelection selection = select();
+ final List<ByteBuffer> values = getColumnValues(selection);
+ final List<Column> columns = new ArrayList<>(values.size());
+ final List<ByteBuffer> names = select().select(settings.columns.names);
+ for (int i = 0 ; i < values.size() ; i++)
+ columns.add(new Column(names.get(i))
+ .setValue(values.get(i))
- .setTimestamp(FBUtilities.timestampMicros()));
++ .setTimestamp(settings.columns.timestamp != null
++ ? Long.parseLong(settings.columns.timestamp)
++ : FBUtilities.timestampMicros()));
+ return columns;
+ }
+
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/047c0461/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
----------------------------------------------------------------------
diff --cc tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
index 4fac5d0,04c2a47..e48b49c
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
@@@ -39,18 -41,13 +41,14 @@@ public class SettingsColumn implements
{
public final int maxColumnsPerKey;
- public final List<ByteBuffer> names;
+ public transient final List<ByteBuffer> names;
public final List<String> namestrs;
public final String comparator;
+ public final String timestamp;
- public final boolean useTimeUUIDComparator;
- public final int superColumns;
- public final boolean useSuperColumns;
public final boolean variableColumnCount;
public final boolean slice;
- private final DistributionFactory sizeDistribution;
- private final DistributionFactory countDistribution;
- private final DataGenFactory dataGenFactory;
+ public final DistributionFactory sizeDistribution;
+ public final DistributionFactory countDistribution;
public SettingsColumn(GroupedOptions options)
{
@@@ -63,11 -60,7 +61,8 @@@
public SettingsColumn(Options options, NameOptions name, CountOptions count)
{
sizeDistribution = options.size.get();
- superColumns = Integer.parseInt(options.superColumns.value());
- dataGenFactory = options.generator.get();
- useSuperColumns = superColumns > 0;
{
+ timestamp = options.timestamp.value();
comparator = options.comparator.value();
AbstractType parsed = null;
@@@ -151,9 -146,7 +148,8 @@@
final OptionSimple superColumns = new OptionSimple("super=", "[0-9]+", "0", "Number of super columns to use (no super columns used if not specified)", false);
final OptionSimple comparator = new OptionSimple("comparator=", "TimeUUIDType|AsciiType|UTF8Type", "AsciiType", "Column Comparator to use", false);
final OptionSimple slice = new OptionSimple("slice", "", null, "If set, range slices will be used for reads, otherwise a names query will be", false);
+ final OptionSimple timestamp = new OptionSimple("timestamp=", "[0-9]+", null, "If set, all columns will be written with the given timestamp", false);
final OptionDistribution size = new OptionDistribution("size=", "FIXED(34)", "Cell size distribution");
- final OptionDataGen generator = new OptionDataGen("data=", "REPEAT(50)");
}
private static final class NameOptions extends Options
@@@ -163,7 -156,7 +159,7 @@@
@Override
public List<? extends Option> options()
{
- return Arrays.asList(name, slice, superColumns, comparator, timestamp, size, generator);
- return Arrays.asList(name, slice, superColumns, comparator, size);
++ return Arrays.asList(name, slice, superColumns, comparator, timestamp, size);
}
}
@@@ -174,7 -167,7 +170,7 @@@
@Override
public List<? extends Option> options()
{
- return Arrays.asList(count, slice, superColumns, comparator, timestamp, size, generator);
- return Arrays.asList(count, slice, superColumns, comparator, size);
++ return Arrays.asList(count, slice, superColumns, comparator, timestamp, size);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/047c0461/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
----------------------------------------------------------------------
[21/23] git commit: Merge branch 'cassandra-2.1.0' into cassandra-2.1
Posted by be...@apache.org.
Merge branch 'cassandra-2.1.0' into cassandra-2.1
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/35b88c56
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/35b88c56
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/35b88c56
Branch: refs/heads/trunk
Commit: 35b88c560f8a294a4502f83901647d34f6532863
Parents: 4e53152 7536429
Author: Benedict Elliott Smith <be...@apache.org>
Authored: Mon Jul 7 18:25:27 2014 +0100
Committer: Benedict Elliott Smith <be...@apache.org>
Committed: Mon Jul 7 18:25:27 2014 +0100
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../cassandra/thrift/ThriftConversion.java | 19 +
.../org/apache/cassandra/utils/UUIDGen.java | 8 +
tools/bin/cassandra-stress | 2 +-
tools/cqlstress-counter-example.yaml | 85 +++
tools/cqlstress-example.yaml | 99 +++
tools/cqlstress-insanity-example.yaml | 102 +++
.../org/apache/cassandra/stress/Operation.java | 218 +-----
.../apache/cassandra/stress/StressAction.java | 262 +++----
.../apache/cassandra/stress/StressMetrics.java | 17 +-
.../apache/cassandra/stress/StressProfile.java | 504 +++++++++++++
.../org/apache/cassandra/stress/StressYaml.java | 38 +
.../cassandra/stress/generate/Distribution.java | 57 ++
.../generate/DistributionBoundApache.java | 84 +++
.../stress/generate/DistributionFactory.java | 31 +
.../stress/generate/DistributionFixed.java | 54 ++
.../stress/generate/DistributionInverted.java | 37 +
.../generate/DistributionOffsetApache.java | 80 +++
.../cassandra/stress/generate/Partition.java | 343 +++++++++
.../stress/generate/PartitionGenerator.java | 80 +++
.../stress/generate/RatioDistribution.java | 25 +
.../generate/RatioDistributionFactory.java | 31 +
.../apache/cassandra/stress/generate/Row.java | 22 +
.../stress/generate/SeedGenerator.java | 8 +
.../stress/generate/SeedRandomGenerator.java | 33 +
.../stress/generate/SeedSeriesGenerator.java | 21 +
.../stress/generate/values/Booleans.java | 37 +
.../cassandra/stress/generate/values/Bytes.java | 54 ++
.../cassandra/stress/generate/values/Dates.java | 46 ++
.../stress/generate/values/Doubles.java | 37 +
.../stress/generate/values/Floats.java | 37 +
.../stress/generate/values/Generator.java | 50 ++
.../stress/generate/values/GeneratorConfig.java | 68 ++
.../stress/generate/values/HexBytes.java | 56 ++
.../stress/generate/values/HexStrings.java | 55 ++
.../cassandra/stress/generate/values/Inets.java | 57 ++
.../stress/generate/values/Integers.java | 38 +
.../cassandra/stress/generate/values/Lists.java | 55 ++
.../cassandra/stress/generate/values/Longs.java | 37 +
.../cassandra/stress/generate/values/Sets.java | 54 ++
.../stress/generate/values/Strings.java | 49 ++
.../stress/generate/values/TimeUUIDs.java | 51 ++
.../cassandra/stress/generate/values/UUIDs.java | 39 +
.../cassandra/stress/generatedata/DataGen.java | 39 -
.../stress/generatedata/DataGenBytesRandom.java | 45 --
.../stress/generatedata/DataGenFactory.java | 30 -
.../stress/generatedata/DataGenHex.java | 60 --
.../DataGenHexFromDistribution.java | 66 --
.../generatedata/DataGenHexFromOpIndex.java | 48 --
.../generatedata/DataGenStringDictionary.java | 107 ---
.../generatedata/DataGenStringRepeats.java | 90 ---
.../stress/generatedata/Distribution.java | 40 --
.../generatedata/DistributionBoundApache.java | 63 --
.../generatedata/DistributionFactory.java | 31 -
.../stress/generatedata/DistributionFixed.java | 46 --
.../generatedata/DistributionOffsetApache.java | 61 --
.../generatedata/DistributionSeqBatch.java | 68 --
.../cassandra/stress/generatedata/KeyGen.java | 54 --
.../cassandra/stress/generatedata/RowGen.java | 53 --
.../generatedata/RowGenDistributedSize.java | 116 ---
.../stress/operations/CqlCounterAdder.java | 77 --
.../stress/operations/CqlCounterGetter.java | 69 --
.../operations/CqlIndexedRangeSlicer.java | 118 ---
.../stress/operations/CqlInserter.java | 88 ---
.../stress/operations/CqlMultiGetter.java | 42 --
.../stress/operations/CqlOperation.java | 698 ------------------
.../stress/operations/CqlRangeSlicer.java | 59 --
.../cassandra/stress/operations/CqlReader.java | 91 ---
.../stress/operations/FixedOpDistribution.java | 25 +
.../stress/operations/OpDistribution.java | 11 +
.../operations/OpDistributionFactory.java | 12 +
.../operations/SampledOpDistribution.java | 41 ++
.../SampledOpDistributionFactory.java | 72 ++
.../stress/operations/ThriftCounterAdder.java | 95 ---
.../stress/operations/ThriftCounterGetter.java | 68 --
.../operations/ThriftIndexedRangeSlicer.java | 114 ---
.../stress/operations/ThriftInserter.java | 117 ---
.../stress/operations/ThriftMultiGetter.java | 80 ---
.../stress/operations/ThriftRangeSlicer.java | 85 ---
.../stress/operations/ThriftReader.java | 94 ---
.../operations/predefined/CqlCounterAdder.java | 84 +++
.../operations/predefined/CqlCounterGetter.java | 74 ++
.../operations/predefined/CqlInserter.java | 79 ++
.../operations/predefined/CqlOperation.java | 714 +++++++++++++++++++
.../stress/operations/predefined/CqlReader.java | 87 +++
.../predefined/PredefinedOperation.java | 248 +++++++
.../predefined/ThriftCounterAdder.java | 86 +++
.../predefined/ThriftCounterGetter.java | 66 ++
.../operations/predefined/ThriftInserter.java | 96 +++
.../operations/predefined/ThriftReader.java | 79 ++
.../operations/userdefined/SchemaInsert.java | 144 ++++
.../operations/userdefined/SchemaQuery.java | 86 +++
.../operations/userdefined/SchemaStatement.java | 164 +++++
.../cassandra/stress/settings/Command.java | 24 +-
.../stress/settings/CommandCategory.java | 4 +-
.../stress/settings/OptionAnyProbabilities.java | 78 ++
.../stress/settings/OptionDataGen.java | 203 ------
.../stress/settings/OptionDistribution.java | 75 +-
.../settings/OptionEnumProbabilities.java | 62 ++
.../cassandra/stress/settings/OptionMulti.java | 3 +-
.../settings/OptionRatioDistribution.java | 166 +++++
.../cassandra/stress/settings/OptionSimple.java | 5 +-
.../stress/settings/SettingsColumn.java | 50 +-
.../stress/settings/SettingsCommand.java | 58 +-
.../stress/settings/SettingsCommandMixed.java | 207 ------
.../settings/SettingsCommandPreDefined.java | 145 ++++
.../SettingsCommandPreDefinedMixed.java | 151 ++++
.../stress/settings/SettingsCommandUser.java | 135 ++++
.../cassandra/stress/settings/SettingsKey.java | 27 +-
.../cassandra/stress/settings/SettingsMisc.java | 2 +-
.../cassandra/stress/settings/SettingsMode.java | 6 +-
.../stress/settings/SettingsSchema.java | 77 +-
.../stress/settings/SettingsTransport.java | 2 +-
.../stress/settings/StressSettings.java | 36 +-
.../stress/settings/ValidationType.java | 8 +
.../cassandra/stress/util/JavaDriverClient.java | 19 +-
.../stress/util/SmartThriftClient.java | 4 +-
.../org/apache/cassandra/stress/util/Timer.java | 17 +-
.../cassandra/stress/util/TimingInterval.java | 26 +-
119 files changed, 5861 insertions(+), 3890 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/35b88c56/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 682f599,ff2f586..a0983af
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,10 -1,5 +1,11 @@@
+2.1.1
+ * Improve schema merge performance (CASSANDRA-7444)
+ * Fix NPE when unknown prepared statement ID is used (CASSANDRA-7454)
+ * Adjust MT depth based on # of partition validating (CASSANDRA-5263)
+ * Optimise NativeCell comparisons (CASSANDRA-6755)
+
2.1.0-rc3
+ * Introduce CQL support for stress tool (CASSANDRA-6146)
* Fix ClassCastException processing expired messages (CASSANDRA-7496)
* Fix prepared marker for collections inside UDT (CASSANDRA-7472)
* Remove left-over populate_io_cache_on_flush and replicate_on_write
[19/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/DistributionOffsetApache.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/DistributionOffsetApache.java b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionOffsetApache.java
new file mode 100644
index 0000000..b0e41eb
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/DistributionOffsetApache.java
@@ -0,0 +1,80 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.commons.math3.distribution.AbstractRealDistribution;
+
+public class DistributionOffsetApache extends Distribution
+{
+
+ final AbstractRealDistribution delegate;
+ final long min, delta;
+
+ public DistributionOffsetApache(AbstractRealDistribution delegate, long min, long max)
+ {
+ this.delegate = delegate;
+ this.min = min;
+ this.delta = max - min;
+ }
+
+ public void setSeed(long seed)
+ {
+ delegate.reseedRandomGenerator(seed);
+ }
+
+ @Override
+ public long next()
+ {
+ return offset(min, delta, delegate.sample());
+ }
+
+ public double nextDouble()
+ {
+ return offsetDouble(min, delta, delegate.sample());
+ }
+
+ @Override
+ public long inverseCumProb(double cumProb)
+ {
+ return offset(min, delta, delegate.inverseCumulativeProbability(cumProb));
+ }
+
+ private long offset(long min, long delta, double val)
+ {
+ long r = (long) val;
+ if (r < 0)
+ r = 0;
+ if (r > delta)
+ r = delta;
+ return min + r;
+ }
+
+ private double offsetDouble(long min, long delta, double r)
+ {
+ if (r < 0)
+ r = 0;
+ if (r > delta)
+ r = delta;
+ return min + r;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/Partition.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/Partition.java b/tools/stress/src/org/apache/cassandra/stress/generate/Partition.java
new file mode 100644
index 0000000..856d550
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/Partition.java
@@ -0,0 +1,343 @@
+package org.apache.cassandra.stress.generate;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Queue;
+import java.util.Random;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.BytesType;
+import org.apache.cassandra.stress.generate.values.Generator;
+
+// a partition is re-used to reduce garbage generation, as is its internal RowIterator
+public class Partition
+{
+
+ private long idseed;
+ private final Object[] partitionKey;
+ private final PartitionGenerator generator;
+ private final RowIterator iterator;
+
+ public Partition(PartitionGenerator generator)
+ {
+ this.generator = generator;
+ this.partitionKey = new Object[generator.partitionKey.size()];
+ if (generator.clusteringComponents.size() > 0)
+ iterator = new MultiRowIterator();
+ else
+ iterator = new SingleRowIterator();
+ }
+
+ void setSeed(long seed)
+ {
+ long idseed = 0;
+ for (int i = 0 ; i < partitionKey.length ; i++)
+ {
+ Generator generator = this.generator.partitionKey.get(i);
+ // set the partition key seed based on the current work item we're processing
+ generator.setSeed(seed);
+ Object key = generator.generate();
+ partitionKey[i] = key;
+ // then contribute this value to the data seed
+ idseed = seed(key, generator.type, idseed);
+ }
+ this.idseed = idseed;
+ }
+
+ public RowIterator iterator(double useChance)
+ {
+ iterator.reset(useChance, 0);
+ return iterator;
+ }
+
+ public RowIterator iterator(int targetCount)
+ {
+ iterator.reset(Double.NaN, targetCount);
+ return iterator;
+ }
+
+ class SingleRowIterator extends RowIterator
+ {
+ boolean done;
+
+ void reset(double useChance, int targetCount)
+ {
+ done = false;
+ }
+
+ public Iterable<Row> batch(double ratio)
+ {
+ if (done)
+ return Collections.emptyList();
+ for (int i = 0 ; i < row.row.length ; i++)
+ {
+ Generator gen = generator.valueComponents.get(i);
+ gen.setSeed(idseed);
+ row.row[i] = gen.generate();
+ }
+ done = true;
+ return Collections.singleton(row);
+ }
+
+ public boolean done()
+ {
+ return done;
+ }
+ }
+
+ public abstract class RowIterator
+ {
+ // we reuse the row object to save garbage
+ final Row row = new Row(partitionKey, new Object[generator.clusteringComponents.size() + generator.valueComponents.size()]);
+
+ public abstract Iterable<Row> batch(double ratio);
+ abstract void reset(double useChance, int targetCount);
+
+ public abstract boolean done();
+
+ public Partition partition()
+ {
+ return Partition.this;
+ }
+ }
+
+ // permits iterating a random subset of the procedurally generated rows in this partition; this is the only mechanism for visiting rows
+ // we maintain a stack of clustering components and their seeds; for each clustering component we visit, we generate all values it takes at that level,
+ // and then, using the average (total) number of children it takes we randomly choose whether or not we visit its children;
+ // if we do, we generate all possible values the children can take, and repeat the process. So at any one time we are using space proportional
+ // to C.N, where N is the average number of values each clustering component takes, as opposed to N^C total values in the partition.
+ class MultiRowIterator extends RowIterator
+ {
+
+ // probability any single row will be generated in this iteration
+ double useChance;
+ double expectedRowCount;
+
+ // the current seed in use at any given level; used to save recalculating it for each row, so we only need to recalc
+ // from prior row
+ final long[] clusteringSeeds = new long[generator.clusteringComponents.size()];
+ // the components remaining to be visited for each level of the current stack
+ final Queue<Object>[] clusteringComponents = new ArrayDeque[generator.clusteringComponents.size()];
+
+ // we want our chance of selection to be applied uniformly, so we compound the roll we make at each level
+ // so that we know with what chance we reached there, and we adjust our roll at that level by that amount
+ double[] chancemodifier = new double[generator.clusteringComponents.size()];
+ double[] rollmodifier = new double[generator.clusteringComponents.size()];
+
+ // reusable set for generating unique clustering components
+ final Set<Object> unique = new HashSet<>();
+ final Random random = new Random();
+
+ MultiRowIterator()
+ {
+ for (int i = 0 ; i < clusteringComponents.length ; i++)
+ clusteringComponents[i] = new ArrayDeque<>();
+ rollmodifier[0] = 1f;
+ chancemodifier[0] = generator.clusteringChildAverages[0];
+ }
+
+ void reset(double useChance, int targetCount)
+ {
+ generator.clusteringComponents.get(0).setSeed(idseed);
+ int firstComponentCount = (int) generator.clusteringComponents.get(0).clusteringDistribution.next();
+ this.expectedRowCount = firstComponentCount * generator.clusteringChildAverages[0];
+ if (Double.isNaN(useChance))
+ useChance = Math.max(0d, Math.min(1d, targetCount / expectedRowCount));
+
+ for (Queue<?> q : clusteringComponents)
+ q.clear();
+
+ this.useChance = useChance;
+ clusteringSeeds[0] = idseed;
+ clusteringComponents[0].add(this);
+ fill(clusteringComponents[0], firstComponentCount, generator.clusteringComponents.get(0));
+ advance(0, 1f);
+ }
+
+ void fill(int component)
+ {
+ long seed = clusteringSeeds[component - 1];
+ Generator gen = generator.clusteringComponents.get(component);
+ gen.setSeed(seed);
+ clusteringSeeds[component] = seed(clusteringComponents[component - 1].peek(), generator.clusteringComponents.get(component - 1).type, seed);
+ fill(clusteringComponents[component], (int) gen.clusteringDistribution.next(), gen);
+ }
+
+ void fill(Queue<Object> queue, int count, Generator generator)
+ {
+ if (count == 1)
+ {
+ queue.add(generator.generate());
+ }
+ else
+ {
+ unique.clear();
+ for (int i = 0 ; i < count ; i++)
+ {
+ Object next = generator.generate();
+ if (unique.add(next))
+ queue.add(next);
+ }
+ }
+ }
+
+ private boolean advance(double continueChance)
+ {
+ // we always start at the leaf level
+ int depth = clusteringComponents.length - 1;
+ // fill the row with the position we *were* at (unless pre-start)
+ for (int i = clusteringSeeds.length ; i < row.row.length ; i++)
+ {
+ Generator gen = generator.valueComponents.get(i - clusteringSeeds.length);
+ long seed = clusteringSeeds[depth];
+ seed = seed(clusteringComponents[depth].peek(), generator.clusteringComponents.get(depth).type, seed);
+ gen.setSeed(seed);
+ row.row[i] = gen.generate();
+ }
+ clusteringComponents[depth].poll();
+
+ return advance(depth, continueChance);
+ }
+
+ private boolean advance(int depth, double continueChance)
+ {
+ // advance the leaf component
+ clusteringComponents[depth].poll();
+ while (true)
+ {
+ if (clusteringComponents[depth].isEmpty())
+ {
+ if (depth == 0)
+ return false;
+ depth--;
+ clusteringComponents[depth].poll();
+ continue;
+ }
+
+ // the chance of descending is the uniform use chance, multiplied by the number of children
+ // we would on average generate (so if we have a 0.1 use chance, but should generate 10 children
+ // then we will always descend), multiplied by 1/(compound roll), where (compound roll) is the
+ // chance with which we reached this depth, i.e. if we already beat 50/50 odds, we double our
+ // chance of beating this next roll
+ double thischance = useChance * chancemodifier[depth];
+ if (thischance > 0.999f || thischance >= random.nextDouble())
+ {
+ row.row[depth] = clusteringComponents[depth].peek();
+ depth++;
+ if (depth == clusteringComponents.length)
+ break;
+ rollmodifier[depth] = rollmodifier[depth - 1] / Math.min(1d, thischance);
+ chancemodifier[depth] = generator.clusteringChildAverages[depth] * rollmodifier[depth];
+ fill(depth);
+ continue;
+ }
+
+ clusteringComponents[depth].poll();
+ }
+
+ return continueChance >= 1.0d || continueChance >= random.nextDouble();
+ }
+
+ public Iterable<Row> batch(final double ratio)
+ {
+ final double continueChance = 1d - (Math.pow(ratio, expectedRowCount * useChance));
+ return new Iterable<Row>()
+ {
+ public Iterator<Row> iterator()
+ {
+ return new Iterator<Row>()
+ {
+ boolean hasNext = true;
+ public boolean hasNext()
+ {
+ return hasNext;
+ }
+
+ public Row next()
+ {
+ hasNext = advance(continueChance);
+ return row;
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ }
+
+ public boolean done()
+ {
+ return clusteringComponents[0].isEmpty();
+ }
+
+ public Partition partition()
+ {
+ return Partition.this;
+ }
+ }
+
+ public String getKeyAsString()
+ {
+ StringBuilder sb = new StringBuilder();
+ int i = 0;
+ for (Object key : partitionKey)
+ {
+ if (i > 0)
+ sb.append("|");
+ AbstractType type = generator.partitionKey.get(i++).type;
+ sb.append(type.getString(type.decompose(key)));
+ }
+ return sb.toString();
+ }
+
+ static long seed(Object object, AbstractType type, long seed)
+ {
+ if (object instanceof ByteBuffer)
+ {
+ ByteBuffer buf = (ByteBuffer) object;
+ for (int i = buf.position() ; i < buf.limit() ; i++)
+ seed = (31 * seed) + buf.get(i);
+ return seed;
+ }
+ else if (object instanceof String)
+ {
+ String str = (String) object;
+ for (int i = 0 ; i < str.length() ; i++)
+ seed = (31 * seed) + str.charAt(i);
+ return seed;
+ }
+ else if (object instanceof Number)
+ {
+ return (seed * 31) + ((Number) object).longValue();
+ }
+ else if (object instanceof UUID)
+ {
+ return seed * 31 + (((UUID) object).getLeastSignificantBits() ^ ((UUID) object).getMostSignificantBits());
+ }
+ else
+ {
+ return seed(type.decompose(object), BytesType.instance, seed);
+ }
+ }
+
+ public Object getPartitionKey(int i)
+ {
+ return partitionKey[i];
+ }
+
+ // used for thrift smart routing - if it's a multi-part key we don't try to route correctly right now
+ public ByteBuffer getToken()
+ {
+ return generator.partitionKey.get(0).type.decompose(partitionKey[0]);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/PartitionGenerator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/PartitionGenerator.java b/tools/stress/src/org/apache/cassandra/stress/generate/PartitionGenerator.java
new file mode 100644
index 0000000..78002fb
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/PartitionGenerator.java
@@ -0,0 +1,80 @@
+package org.apache.cassandra.stress.generate;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import com.google.common.collect.Iterables;
+
+import org.apache.cassandra.stress.generate.values.Generator;
+
+public class PartitionGenerator
+{
+
+ public final double maxRowCount;
+ final List<Generator> partitionKey;
+ final List<Generator> clusteringComponents;
+ final List<Generator> valueComponents;
+ final int[] clusteringChildAverages;
+
+ private final Map<String, Integer> indexMap;
+
+ final List<Partition> recyclable = new ArrayList<>();
+ int partitionsInUse = 0;
+
+ public void reset()
+ {
+ partitionsInUse = 0;
+ }
+
+ public PartitionGenerator(List<Generator> partitionKey, List<Generator> clusteringComponents, List<Generator> valueComponents)
+ {
+ this.partitionKey = partitionKey;
+ this.clusteringComponents = clusteringComponents;
+ this.valueComponents = valueComponents;
+ this.clusteringChildAverages = new int[clusteringComponents.size()];
+ for (int i = clusteringChildAverages.length - 1 ; i >= 0 ; i--)
+ clusteringChildAverages[i] = (int) (i < (clusteringChildAverages.length - 1) ? clusteringComponents.get(i + 1).clusteringDistribution.average() * clusteringChildAverages[i + 1] : 1);
+ double maxRowCount = 1d;
+ for (Generator component : clusteringComponents)
+ maxRowCount *= component.clusteringDistribution.maxValue();
+ this.maxRowCount = maxRowCount;
+ this.indexMap = new HashMap<>();
+ int i = 0;
+ for (Generator generator : partitionKey)
+ indexMap.put(generator.name, --i);
+ i = 0;
+ for (Generator generator : Iterables.concat(clusteringComponents, valueComponents))
+ indexMap.put(generator.name, i++);
+ }
+
+ public int indexOf(String name)
+ {
+ Integer i = indexMap.get(name);
+ if (i == null)
+ throw new NoSuchElementException();
+ return i;
+ }
+
+ public Partition generate(long seed)
+ {
+ if (recyclable.size() <= partitionsInUse || recyclable.get(partitionsInUse) == null)
+ recyclable.add(new Partition(this));
+
+ Partition partition = recyclable.get(partitionsInUse++);
+ partition.setSeed(seed);
+ return partition;
+ }
+
+ public ByteBuffer convert(int c, Object v)
+ {
+ if (c < 0)
+ return partitionKey.get(-1-c).type.decompose(v);
+ if (c < clusteringComponents.size())
+ return clusteringComponents.get(c).type.decompose(v);
+ return valueComponents.get(c - clusteringComponents.size()).type.decompose(v);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistribution.java b/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistribution.java
new file mode 100644
index 0000000..fb5a373
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistribution.java
@@ -0,0 +1,25 @@
+package org.apache.cassandra.stress.generate;
+
+public class RatioDistribution
+{
+
+ final Distribution distribution;
+ final double divisor;
+
+ public RatioDistribution(Distribution distribution, double divisor)
+ {
+ this.distribution = distribution;
+ this.divisor = divisor;
+ }
+
+ // yields a value between 0 and 1
+ public double next()
+ {
+ return Math.max(0f, Math.min(1f, distribution.nextDouble() / divisor));
+ }
+
+ public double max()
+ {
+ return Math.min(1d, distribution.maxValue() / divisor);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistributionFactory.java
new file mode 100644
index 0000000..16474d8
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/RatioDistributionFactory.java
@@ -0,0 +1,31 @@
+package org.apache.cassandra.stress.generate;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.Serializable;
+
+public interface RatioDistributionFactory extends Serializable
+{
+
+ RatioDistribution get();
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/Row.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/Row.java b/tools/stress/src/org/apache/cassandra/stress/generate/Row.java
new file mode 100644
index 0000000..d3b9a2a
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/Row.java
@@ -0,0 +1,22 @@
+package org.apache.cassandra.stress.generate;
+
+public class Row
+{
+
+ final Object[] partitionKey;
+ final Object[] row;
+
+ public Row(Object[] partitionKey, Object[] row)
+ {
+ this.partitionKey = partitionKey;
+ this.row = row;
+ }
+
+ public Object get(int column)
+ {
+ if (column < 0)
+ return partitionKey[-1-column];
+ return row[column];
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/SeedGenerator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/SeedGenerator.java b/tools/stress/src/org/apache/cassandra/stress/generate/SeedGenerator.java
new file mode 100644
index 0000000..6c1bc7f
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/SeedGenerator.java
@@ -0,0 +1,8 @@
+package org.apache.cassandra.stress.generate;
+
+public interface SeedGenerator
+{
+
+ long next(long workIndex);
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/SeedRandomGenerator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/SeedRandomGenerator.java b/tools/stress/src/org/apache/cassandra/stress/generate/SeedRandomGenerator.java
new file mode 100644
index 0000000..bbaaeb8
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/SeedRandomGenerator.java
@@ -0,0 +1,33 @@
+package org.apache.cassandra.stress.generate;
+
+public class SeedRandomGenerator implements SeedGenerator
+{
+
+ final Distribution distribution;
+ final Distribution clustering;
+
+ private long next;
+ private int count;
+
+ public SeedRandomGenerator(Distribution distribution, Distribution clustering)
+ {
+ this.distribution = distribution;
+ this.clustering = clustering;
+ }
+
+ public long next(long workIndex)
+ {
+ if (count == 0)
+ {
+ next = distribution.next();
+ count = (int) clustering.next();
+ }
+ long result = next;
+ count--;
+ if (next == distribution.maxValue())
+ next = distribution.minValue();
+ else
+ next++;
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/SeedSeriesGenerator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/SeedSeriesGenerator.java b/tools/stress/src/org/apache/cassandra/stress/generate/SeedSeriesGenerator.java
new file mode 100644
index 0000000..27967d2
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/SeedSeriesGenerator.java
@@ -0,0 +1,21 @@
+package org.apache.cassandra.stress.generate;
+
+public class SeedSeriesGenerator implements SeedGenerator
+{
+
+ final long min;
+ final long count;
+
+ public SeedSeriesGenerator(long min, long max)
+ {
+ if (min > max)
+ throw new IllegalStateException();
+ this.min = min;
+ this.count = 1 + max - min;
+ }
+
+ public long next(long workIndex)
+ {
+ return min + (workIndex % count);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Booleans.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Booleans.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Booleans.java
new file mode 100644
index 0000000..b1d84d6
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Booleans.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.BooleanType;
+
+public class Booleans extends Generator<Boolean>
+{
+ public Booleans(String name, GeneratorConfig config)
+ {
+ super(BooleanType.instance, config, name);
+ }
+
+ @Override
+ public Boolean generate()
+ {
+ return identityDistribution.next() % 1 == 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Bytes.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Bytes.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Bytes.java
new file mode 100644
index 0000000..2a5bddf
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Bytes.java
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.BytesType;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
+
+public class Bytes extends Generator<ByteBuffer>
+{
+ private final byte[] bytes;
+ private final Random rand = new Random();
+
+ public Bytes(String name, GeneratorConfig config)
+ {
+ super(BytesType.instance, config, name);
+ bytes = new byte[(int) sizeDistribution.maxValue()];
+ }
+
+ @Override
+ public ByteBuffer generate()
+ {
+ long seed = identityDistribution.next();
+ sizeDistribution.setSeed(seed);
+ rand.setSeed(~seed);
+ int size = (int) sizeDistribution.next();
+ for (int i = 0; i < size; )
+ for (int v = rand.nextInt(),
+ n = Math.min(size - i, Integer.SIZE/Byte.SIZE);
+ n-- > 0; v >>= Byte.SIZE)
+ bytes[i++] = (byte)v;
+ return ByteBuffer.wrap(Arrays.copyOf(bytes, size));
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Dates.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Dates.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Dates.java
new file mode 100644
index 0000000..7d36be2
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Dates.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.util.Date;
+
+import org.apache.cassandra.db.marshal.DateType;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.settings.OptionDistribution;
+
+public class Dates extends Generator<Date>
+{
+ public Dates(String name, GeneratorConfig config)
+ {
+ super(DateType.instance, config, name);
+ }
+
+ @Override
+ public Date generate()
+ {
+ return new Date(identityDistribution.next());
+ }
+
+ DistributionFactory defaultIdentityDistribution()
+ {
+ return OptionDistribution.get("uniform(1.." + Long.toString(50L*365L*24L*60L*60L*1000L) + ")");
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Doubles.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Doubles.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Doubles.java
new file mode 100644
index 0000000..76e983d
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Doubles.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.DoubleType;
+
+public class Doubles extends Generator<Double>
+{
+ public Doubles(String name, GeneratorConfig config)
+ {
+ super(DoubleType.instance, config, name);
+ }
+
+ @Override
+ public Double generate()
+ {
+ return identityDistribution.nextDouble();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Floats.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Floats.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Floats.java
new file mode 100644
index 0000000..8e23c11
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Floats.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.FloatType;
+
+public class Floats extends Generator<Float>
+{
+ public Floats(String name, GeneratorConfig config)
+ {
+ super(FloatType.instance, config, name);
+ }
+
+ @Override
+ public Float generate()
+ {
+ return (float) identityDistribution.nextDouble();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Generator.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Generator.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Generator.java
new file mode 100644
index 0000000..13343de
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Generator.java
@@ -0,0 +1,50 @@
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.settings.OptionDistribution;
+
+public abstract class Generator<T>
+{
+
+ public final String name;
+ public final AbstractType<T> type;
+ final long salt;
+ final Distribution identityDistribution;
+ final Distribution sizeDistribution;
+ public final Distribution clusteringDistribution;
+
+ public Generator(AbstractType<T> type, GeneratorConfig config, String name)
+ {
+ this.type = type;
+ this.name = name;
+ this.salt = config.salt;
+ this.identityDistribution = config.getIdentityDistribution(defaultIdentityDistribution());
+ this.sizeDistribution = config.getSizeDistribution(defaultSizeDistribution());
+ this.clusteringDistribution = config.getClusteringDistribution(defaultClusteringDistribution());
+ }
+
+ public void setSeed(long seed)
+ {
+ identityDistribution.setSeed(seed ^ salt);
+ clusteringDistribution.setSeed(seed ^ ~salt);
+ }
+
+ public abstract T generate();
+
+ DistributionFactory defaultIdentityDistribution()
+ {
+ return OptionDistribution.get("uniform(1..100B)");
+ }
+
+ DistributionFactory defaultSizeDistribution()
+ {
+ return OptionDistribution.get("uniform(4..8)");
+ }
+
+ DistributionFactory defaultClusteringDistribution()
+ {
+ return OptionDistribution.get("fixed(1)");
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/GeneratorConfig.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/GeneratorConfig.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/GeneratorConfig.java
new file mode 100644
index 0000000..8f7b2ea
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/GeneratorConfig.java
@@ -0,0 +1,68 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.MurmurHash;
+
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.Map;
+
+public class GeneratorConfig implements Serializable
+{
+ public final long salt;
+
+ private final DistributionFactory clusteringDistributions;
+ private final DistributionFactory sizeDistributions;
+ private final DistributionFactory identityDistributions;
+
+ public GeneratorConfig(String seedStr, DistributionFactory clusteringDistributions, DistributionFactory sizeDistributions, DistributionFactory identityDistributions)
+ {
+ this.clusteringDistributions = clusteringDistributions;
+ this.sizeDistributions = sizeDistributions;
+ this.identityDistributions = identityDistributions;
+ ByteBuffer buf = ByteBufferUtil.bytes(seedStr);
+ long[] hash = new long[2];
+ MurmurHash.hash3_x64_128(buf, buf.position(), buf.remaining(), 0, hash);
+ salt = hash[0];
+ }
+
+ Distribution getClusteringDistribution(DistributionFactory deflt)
+ {
+ return (clusteringDistributions == null ? deflt : clusteringDistributions).get();
+ }
+
+ Distribution getIdentityDistribution(DistributionFactory deflt)
+ {
+ return (identityDistributions == null ? deflt : identityDistributions).get();
+ }
+
+ Distribution getSizeDistribution(DistributionFactory deflt)
+ {
+ return (sizeDistributions == null ? deflt : sizeDistributions).get();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/HexBytes.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/HexBytes.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/HexBytes.java
new file mode 100644
index 0000000..db46bac
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/HexBytes.java
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import org.apache.cassandra.db.marshal.BytesType;
+
+public class HexBytes extends Generator<ByteBuffer>
+{
+ private final byte[] bytes;
+
+ public HexBytes(String name, GeneratorConfig config)
+ {
+ super(BytesType.instance, config, name);
+ bytes = new byte[(int) sizeDistribution.maxValue()];
+ }
+
+ @Override
+ public ByteBuffer generate()
+ {
+ long seed = identityDistribution.next();
+ sizeDistribution.setSeed(seed);
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i +=16)
+ {
+ long value = identityDistribution.next();
+ for (int j = 0 ; j < 16 && i + j < size ; j++)
+ {
+ int v = (int) (value & 15);
+ bytes[i + j] = (byte) ((v < 10 ? '0' : 'A') + v);
+ value >>>= 4;
+ }
+ }
+ return ByteBuffer.wrap(Arrays.copyOf(bytes, size));
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/HexStrings.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/HexStrings.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/HexStrings.java
new file mode 100644
index 0000000..ce65b8a
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/HexStrings.java
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.util.Random;
+
+import org.apache.cassandra.db.marshal.UTF8Type;
+
+public class HexStrings extends Generator<String>
+{
+ private final char[] chars;
+
+ public HexStrings(String name, GeneratorConfig config)
+ {
+ super(UTF8Type.instance, config, name);
+ chars = new char[(int) sizeDistribution.maxValue()];
+ }
+
+ @Override
+ public String generate()
+ {
+ long seed = identityDistribution.next();
+ sizeDistribution.setSeed(seed);
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i +=16)
+ {
+ long value = identityDistribution.next();
+ for (int j = 0 ; j < 16 && i + j < size ; j++)
+ {
+ int v = (int) (value & 15);
+ chars[i + j] = (char) ((v < 10 ? '0' : 'A') + v);
+ value >>>= 4;
+ }
+ }
+ return new String(chars, 0, size);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Inets.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Inets.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Inets.java
new file mode 100644
index 0000000..334d73c
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Inets.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.apache.cassandra.db.marshal.InetAddressType;
+
+
+public class Inets extends Generator<InetAddress>
+{
+ final byte[] buf;
+ public Inets(String name, GeneratorConfig config)
+ {
+ super(InetAddressType.instance, config, name);
+ buf = new byte[4];
+ }
+
+ @Override
+ public InetAddress generate()
+ {
+ int val = (int) identityDistribution.next();
+
+ buf[0] = (byte)(val >>> 24);
+ buf[1] = (byte)(val >>> 16);
+ buf[2] = (byte)(val >>> 8);
+ buf[3] = (byte)val;
+
+ try
+ {
+ return InetAddress.getByAddress(buf);
+ }
+ catch (UnknownHostException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Integers.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Integers.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Integers.java
new file mode 100644
index 0000000..8b9b33a
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Integers.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.Int32Type;
+
+public class Integers extends Generator<Integer>
+{
+
+ public Integers(String name, GeneratorConfig config)
+ {
+ super(Int32Type.instance, config, name);
+ }
+
+ @Override
+ public Integer generate()
+ {
+ return (int) identityDistribution.next();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
new file mode 100644
index 0000000..d188f7e
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
@@ -0,0 +1,55 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.cassandra.db.marshal.ListType;
+
+public class Lists extends Generator<List>
+{
+ final Generator valueType;
+ final Object[] buffer;
+
+ public Lists(String name, Generator valueType, GeneratorConfig config)
+ {
+ super(ListType.getInstance(valueType.type), config, name);
+ this.valueType = valueType;
+ buffer = new Object[(int) sizeDistribution.maxValue()];
+ }
+
+ public void setSeed(long seed)
+ {
+ super.setSeed(seed);
+ valueType.setSeed(seed * 31);
+ }
+
+ @Override
+ public List generate()
+ {
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i++)
+ buffer[i] = valueType.generate();
+ return com.google.common.collect.Lists.newArrayList(Arrays.copyOf(buffer, size));
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Longs.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Longs.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Longs.java
new file mode 100644
index 0000000..0584ed1
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Longs.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import org.apache.cassandra.db.marshal.LongType;
+
+public class Longs extends Generator<Long>
+{
+ public Longs(String name, GeneratorConfig config)
+ {
+ super(LongType.instance, config, name);
+ }
+
+ @Override
+ public Long generate()
+ {
+ return identityDistribution.next();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
new file mode 100644
index 0000000..48bf293
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.cassandra.db.marshal.SetType;
+
+public class Sets extends Generator<Set>
+{
+ final Generator valueType;
+
+ public Sets(String name, Generator valueType, GeneratorConfig config)
+ {
+ super(SetType.getInstance(valueType.type), config, name);
+ this.valueType = valueType;
+ }
+
+ public void setSeed(long seed)
+ {
+ super.setSeed(seed);
+ valueType.setSeed(seed * 31);
+ }
+
+ @Override
+ public Set generate()
+ {
+ final Set set = new HashSet();
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i++)
+ set.add(valueType.generate());
+ return set;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/Strings.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Strings.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Strings.java
new file mode 100644
index 0000000..e01ff20
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Strings.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.util.Random;
+
+import org.apache.cassandra.db.marshal.UTF8Type;
+
+public class Strings extends Generator<String>
+{
+ private final char[] chars;
+ private final Random rnd = new Random();
+
+ public Strings(String name, GeneratorConfig config)
+ {
+ super(UTF8Type.instance, config, name);
+ chars = new char[(int) sizeDistribution.maxValue()];
+ }
+
+ @Override
+ public String generate()
+ {
+ long seed = identityDistribution.next();
+ sizeDistribution.setSeed(seed);
+ rnd.setSeed(~seed);
+ int size = (int) sizeDistribution.next();
+ for (int i = 0 ; i < size ; i++)
+ chars[i] = (char) (32 +rnd.nextInt(128-32));
+ return new String(chars, 0, size);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java
new file mode 100644
index 0000000..714959d
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/TimeUUIDs.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+
+import org.apache.cassandra.db.marshal.TimeUUIDType;
+import org.apache.cassandra.utils.UUIDGen;
+
+import java.util.UUID;
+
+public class TimeUUIDs extends Generator<UUID>
+{
+ final Dates dateGen;
+ final long clockSeqAndNode;
+
+ public TimeUUIDs(String name, GeneratorConfig config)
+ {
+ super(TimeUUIDType.instance, config, name);
+ dateGen = new Dates(name, config);
+ clockSeqAndNode = config.salt;
+ }
+
+ public void setSeed(long seed)
+ {
+ dateGen.setSeed(seed);
+ }
+
+ @Override
+ public UUID generate()
+ {
+ return UUIDGen.getTimeUUID(dateGen.generate().getTime(), clockSeqAndNode);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generate/values/UUIDs.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/UUIDs.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/UUIDs.java
new file mode 100644
index 0000000..e8d6501
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/UUIDs.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.cassandra.stress.generate.values;
+
+import java.util.UUID;
+
+import org.apache.cassandra.db.marshal.UUIDType;
+
+public class UUIDs extends Generator<UUID>
+{
+ public UUIDs(String name, GeneratorConfig config)
+ {
+ super(UUIDType.instance, config, name);
+ }
+
+ @Override
+ public UUID generate()
+ {
+ return new UUID(identityDistribution.next(), identityDistribution.next());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGen.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGen.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGen.java
deleted file mode 100644
index 334506d..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGen.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.List;
-
-public abstract class DataGen
-{
-
- public abstract void generate(ByteBuffer fill, long index, ByteBuffer seed);
- public abstract boolean isDeterministic();
-
- public void generate(List<ByteBuffer> fills, long index, ByteBuffer seed)
- {
- for (ByteBuffer fill : fills)
- generate(fill, index++, seed);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenBytesRandom.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenBytesRandom.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenBytesRandom.java
deleted file mode 100644
index 1dc77b4..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenBytesRandom.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.util.Random;
-
-public class DataGenBytesRandom extends DataGen
-{
-
- private final Random rnd = new Random();
-
- @Override
- public void generate(ByteBuffer fill, long index, ByteBuffer seed)
- {
- fill.clear();
- rnd.nextBytes(fill.array());
- }
-
- @Override
- public boolean isDeterministic()
- {
- return false;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenFactory.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenFactory.java
deleted file mode 100644
index dadb792..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenFactory.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.Serializable;
-
-public interface DataGenFactory extends Serializable
-{
- DataGen get();
-}
-
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHex.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHex.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHex.java
deleted file mode 100644
index 124a07b..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHex.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-
-public abstract class DataGenHex extends DataGen
-{
-
- abstract long next(long operationIndex);
-
- @Override
- public final void generate(ByteBuffer fill, long operationIndex, ByteBuffer seed)
- {
- fill.clear();
- fillKeyStringBytes(next(operationIndex), fill.array());
- }
-
- public static void fillKeyStringBytes(long key, byte[] fill)
- {
- int ub = fill.length - 1;
- int offset = 0;
- while (key != 0)
- {
- int digit = ((int) key) & 15;
- key >>>= 4;
- fill[ub - offset++] = digit(digit);
- }
- while (offset < fill.length)
- fill[ub - offset++] = '0';
- }
-
- // needs to be UTF-8, but for these chars there is no difference
- private static byte digit(int num)
- {
- if (num < 10)
- return (byte)('0' + num);
- return (byte)('A' + (num - 10));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromDistribution.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromDistribution.java
deleted file mode 100644
index 25284dc..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromDistribution.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import org.apache.commons.math3.distribution.NormalDistribution;
-import org.apache.commons.math3.distribution.UniformRealDistribution;
-
-public class DataGenHexFromDistribution extends DataGenHex
-{
-
- final Distribution distribution;
-
- public DataGenHexFromDistribution(Distribution distribution)
- {
- this.distribution = distribution;
- }
-
- @Override
- public boolean isDeterministic()
- {
- return false;
- }
-
- @Override
- long next(long operationIndex)
- {
- return distribution.next();
- }
-
- public static DataGenHex buildGaussian(long minKey, long maxKey, double stdevsToLimit)
- {
- double midRange = (maxKey + minKey) / 2d;
- double halfRange = (maxKey - minKey) / 2d;
- return new DataGenHexFromDistribution(new DistributionBoundApache(new NormalDistribution(midRange, halfRange / stdevsToLimit), minKey, maxKey));
- }
-
- public static DataGenHex buildGaussian(long minKey, long maxKey, double mean, double stdev)
- {
- return new DataGenHexFromDistribution(new DistributionBoundApache(new NormalDistribution(mean, stdev), minKey, maxKey));
- }
-
- public static DataGenHex buildUniform(long minKey, long maxKey)
- {
- return new DataGenHexFromDistribution(new DistributionBoundApache(new UniformRealDistribution(minKey, maxKey), minKey, maxKey));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromOpIndex.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromOpIndex.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromOpIndex.java
deleted file mode 100644
index e6bda68..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenHexFromOpIndex.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-public class DataGenHexFromOpIndex extends DataGenHex
-{
-
- final long minKey;
- final long maxKey;
-
- public DataGenHexFromOpIndex(long minKey, long maxKey)
- {
- this.minKey = minKey;
- this.maxKey = maxKey;
- }
-
- @Override
- public boolean isDeterministic()
- {
- return true;
- }
-
- @Override
- long next(long operationIndex)
- {
- long range = maxKey + 1 - minKey;
- return Math.abs((operationIndex % range) + minKey);
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringDictionary.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringDictionary.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringDictionary.java
deleted file mode 100644
index 73814cb..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringDictionary.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.math3.distribution.EnumeratedDistribution;
-import org.apache.commons.math3.util.Pair;
-
-import static com.google.common.base.Charsets.UTF_8;
-
-public class DataGenStringDictionary extends DataGen
-{
-
- private final byte space = ' ';
- private final EnumeratedDistribution<byte[]> words;
-
- public DataGenStringDictionary(EnumeratedDistribution<byte[]> wordDistribution)
- {
- words = wordDistribution;
- }
-
- @Override
- public void generate(ByteBuffer fill, long index, ByteBuffer seed)
- {
- fill(fill);
- }
-
- @Override
- public void generate(List<ByteBuffer> fills, long index, ByteBuffer seed)
- {
- for (int i = 0 ; i < fills.size() ; i++)
- fill(fills.get(0));
- }
-
- private void fill(ByteBuffer fill)
- {
- fill.clear();
- byte[] trg = fill.array();
- int i = 0;
- while (i < trg.length)
- {
- if (i > 0)
- trg[i++] = space;
- byte[] src = words.sample();
- System.arraycopy(src, 0, trg, i, Math.min(src.length, trg.length - i));
- i += src.length;
- }
- }
-
- @Override
- public boolean isDeterministic()
- {
- return false;
- }
-
- public static DataGenFactory getFactory(File file) throws IOException
- {
- final List<Pair<byte[], Double>> words = new ArrayList<>();
- try (final BufferedReader reader = new BufferedReader(new FileReader(file)))
- {
- String line;
- while ( null != (line = reader.readLine()) )
- {
- String[] pair = line.split(" +");
- if (pair.length != 2)
- throw new IllegalArgumentException("Invalid record in dictionary: \"" + line + "\"");
- words.add(new Pair<>(pair[1].getBytes(UTF_8), Double.parseDouble(pair[0])));
- }
- final EnumeratedDistribution<byte[]> dist = new EnumeratedDistribution<byte[]>(words);
- return new DataGenFactory()
- {
- @Override
- public DataGen get()
- {
- return new DataGenStringDictionary(dist);
- }
- };
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringRepeats.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringRepeats.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringRepeats.java
deleted file mode 100644
index ad7cb24..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DataGenStringRepeats.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.nio.ByteBuffer;
-import java.security.MessageDigest;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.cassandra.utils.FBUtilities;
-
-import static com.google.common.base.Charsets.UTF_8;
-
-public class DataGenStringRepeats extends DataGen
-{
-
- private static final ConcurrentHashMap<Integer, ConcurrentHashMap<Long, byte[]>> CACHE_LOOKUP = new ConcurrentHashMap<>();
-
- private final ConcurrentHashMap<Long, byte[]> cache;
- private final int repeatFrequency;
- public DataGenStringRepeats(int repeatFrequency)
- {
- if (!CACHE_LOOKUP.containsKey(repeatFrequency))
- CACHE_LOOKUP.putIfAbsent(repeatFrequency, new ConcurrentHashMap<Long, byte[]>());
- cache = CACHE_LOOKUP.get(repeatFrequency);
- this.repeatFrequency = repeatFrequency;
- }
-
- @Override
- public void generate(ByteBuffer fill, long index, ByteBuffer seed)
- {
- fill(fill, index, 0, seed);
- }
-
- @Override
- public void generate(List<ByteBuffer> fills, long index, ByteBuffer seed)
- {
- for (int i = 0 ; i < fills.size() ; i++)
- {
- fill(fills.get(i), index, i, seed);
- }
- }
-
- private void fill(ByteBuffer fill, long index, int column, ByteBuffer seed)
- {
- fill.clear();
- byte[] trg = fill.array();
- byte[] src = getData(index, column, seed);
- for (int j = 0 ; j < trg.length ; j += src.length)
- System.arraycopy(src, 0, trg, j, Math.min(src.length, trg.length - j));
- }
-
- private byte[] getData(long index, int column, ByteBuffer seed)
- {
- final long key = ((long)column * repeatFrequency) + ((seed == null ? index : Math.abs(seed.hashCode())) % repeatFrequency);
- byte[] r = cache.get(key);
- if (r != null)
- return r;
- MessageDigest md = FBUtilities.threadLocalMD5Digest();
- r = md.digest(Long.toString(key).getBytes(UTF_8));
- cache.putIfAbsent(key, r);
- return r;
- }
-
- @Override
- public boolean isDeterministic()
- {
- return true;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/Distribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/Distribution.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/Distribution.java
deleted file mode 100644
index ed40290..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/Distribution.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-public abstract class Distribution
-{
-
- public abstract long next();
- public abstract long inverseCumProb(double cumProb);
-
- public long maxValue()
- {
- return inverseCumProb(1d);
- }
-
- public long minValue()
- {
- return inverseCumProb(0d);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionBoundApache.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionBoundApache.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionBoundApache.java
deleted file mode 100644
index 0fdd437..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionBoundApache.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import org.apache.commons.math3.distribution.AbstractRealDistribution;
-
-public class DistributionBoundApache extends Distribution
-{
-
- final AbstractRealDistribution delegate;
- final long min, max;
-
- public DistributionBoundApache(AbstractRealDistribution delegate, long min, long max)
- {
- this.delegate = delegate;
- this.min = min;
- this.max = max;
- }
-
- @Override
- public long next()
- {
- return bound(min, max, delegate.sample());
- }
-
- @Override
- public long inverseCumProb(double cumProb)
- {
- return bound(min, max, delegate.inverseCumulativeProbability(cumProb));
- }
-
- private static long bound(long min, long max, double val)
- {
- long r = (long) val;
- if ((r >= min) & (r <= max))
- return r;
- if (r < min)
- return min;
- if (r > max)
- return max;
- throw new IllegalStateException();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFactory.java
deleted file mode 100644
index b80f851..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFactory.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.Serializable;
-
-public interface DistributionFactory extends Serializable
-{
-
- Distribution get();
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFixed.java b/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFixed.java
deleted file mode 100644
index 43372ca..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/generatedata/DistributionFixed.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.apache.cassandra.stress.generatedata;
-/*
- *
- * 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.
- *
- */
-
-
-public class DistributionFixed extends Distribution
-{
-
- final long key;
-
- public DistributionFixed(long key)
- {
- this.key = key;
- }
-
- @Override
- public long next()
- {
- return key;
- }
-
- @Override
- public long inverseCumProb(double cumProb)
- {
- return key;
- }
-
-}
[09/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java b/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java
index 2782a05..7ede496 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/SmartThriftClient.java
@@ -63,8 +63,10 @@ public class SmartThriftClient implements ThriftClient
return r;
r = queryIdCounter.incrementAndGet();
if (queryIds.putIfAbsent(query, r) == null)
+ {
+ queryStrings.put(r, query);
return r;
- queryStrings.put(r, query);
+ }
return queryIds.get(query);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/Timer.java b/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
index 06d113d..45e1ba7 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
@@ -43,7 +43,8 @@ public final class Timer
private int opCount;
// aggregate info
- private int keyCount;
+ private long partitionCount;
+ private long rowCount;
private long total;
private long max;
private long maxStart;
@@ -65,7 +66,7 @@ public final class Timer
return 1 + (index >>> SAMPLE_SIZE_SHIFT);
}
- public void stop(int keys)
+ public void stop(long partitionCount, long rowCount)
{
maybeReport();
long now = System.nanoTime();
@@ -79,7 +80,8 @@ public final class Timer
}
total += time;
opCount += 1;
- keyCount += keys;
+ this.partitionCount += partitionCount;
+ this.rowCount += rowCount;
upToDateAsOf = now;
}
@@ -94,11 +96,12 @@ public final class Timer
( new SampleOfLongs(Arrays.copyOf(sample, index(opCount)), p(opCount)),
new SampleOfLongs(Arrays.copyOfRange(sample, index(opCount), Math.min(opCount, sample.length)), p(opCount) - 1)
);
- final TimingInterval report = new TimingInterval(lastSnap, upToDateAsOf, max, maxStart, max, keyCount, total, opCount,
+ final TimingInterval report = new TimingInterval(lastSnap, upToDateAsOf, max, maxStart, max, partitionCount, rowCount, total, opCount,
SampleOfLongs.merge(rnd, sampleLatencies, Integer.MAX_VALUE));
// reset counters
opCount = 0;
- keyCount = 0;
+ partitionCount = 0;
+ rowCount = 0;
total = 0;
max = 0;
lastSnap = upToDateAsOf;
@@ -145,6 +148,4 @@ public final class Timer
reportRequest = null;
}
}
-
-}
-
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java b/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
index 9e68045..db3fef1 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
@@ -39,7 +39,8 @@ public final class TimingInterval
public final long totalLatency;
// discrete
- public final long keyCount;
+ public final long partitionCount;
+ public final long rowCount;
public final long operationCount;
final SampleOfLongs sample;
@@ -48,16 +49,17 @@ public final class TimingInterval
{
start = end = time;
maxLatency = totalLatency = 0;
- keyCount = operationCount = 0;
+ partitionCount = rowCount = operationCount = 0;
pauseStart = pauseLength = 0;
sample = new SampleOfLongs(new long[0], 1d);
}
- TimingInterval(long start, long end, long maxLatency, long pauseStart, long pauseLength, long keyCount, long totalLatency, long operationCount, SampleOfLongs sample)
+ TimingInterval(long start, long end, long maxLatency, long pauseStart, long pauseLength, long partitionCount, long rowCount, long totalLatency, long operationCount, SampleOfLongs sample)
{
this.start = start;
this.end = Math.max(end, start);
this.maxLatency = maxLatency;
- this.keyCount = keyCount;
+ this.partitionCount = partitionCount;
+ this.rowCount = rowCount;
this.totalLatency = totalLatency;
this.operationCount = operationCount;
this.pauseStart = pauseStart;
@@ -68,7 +70,7 @@ public final class TimingInterval
// merge multiple timer intervals together
static TimingInterval merge(Random rnd, List<TimingInterval> intervals, int maxSamples, long start)
{
- int operationCount = 0, keyCount = 0;
+ long operationCount = 0, partitionCount = 0, rowCount = 0;
long maxLatency = 0, totalLatency = 0;
List<SampleOfLongs> latencies = new ArrayList<>();
long end = 0;
@@ -79,7 +81,8 @@ public final class TimingInterval
operationCount += interval.operationCount;
maxLatency = Math.max(interval.maxLatency, maxLatency);
totalLatency += interval.totalLatency;
- keyCount += interval.keyCount;
+ partitionCount += interval.partitionCount;
+ rowCount += interval.rowCount;
latencies.addAll(Arrays.asList(interval.sample));
if (interval.pauseLength > 0)
{
@@ -89,7 +92,7 @@ public final class TimingInterval
}
if (pauseEnd < pauseStart)
pauseEnd = pauseStart = 0;
- return new TimingInterval(start, end, maxLatency, pauseStart, pauseEnd - pauseStart, keyCount, totalLatency, operationCount,
+ return new TimingInterval(start, end, maxLatency, pauseStart, pauseEnd - pauseStart, partitionCount, rowCount, totalLatency, operationCount,
SampleOfLongs.merge(rnd, latencies, maxSamples));
}
@@ -104,9 +107,14 @@ public final class TimingInterval
return operationCount / ((end - (start + pauseLength)) * 0.000000001d);
}
- public double keyRate()
+ public double partitionRate()
{
- return keyCount / ((end - start) * 0.000000001d);
+ return partitionCount / ((end - start) * 0.000000001d);
+ }
+
+ public double rowRate()
+ {
+ return rowCount / ((end - start) * 0.000000001d);
}
public double meanLatency()
[16/23] Introduce CQL support for stress tool
Posted by be...@apache.org.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionAnyProbabilities.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionAnyProbabilities.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionAnyProbabilities.java
new file mode 100644
index 0000000..a9af1bd
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionAnyProbabilities.java
@@ -0,0 +1,78 @@
+package org.apache.cassandra.stress.settings;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.math3.util.Pair;
+
+public final class OptionAnyProbabilities extends OptionMulti
+{
+ public OptionAnyProbabilities(String name, String description)
+ {
+ super(name, description, false);
+ }
+
+ final CollectRatios ratios = new CollectRatios();
+
+ private static final class CollectRatios extends Option
+ {
+ Map<String, Double> options = new LinkedHashMap<>();
+
+ boolean accept(String param)
+ {
+ String[] args = param.split("=");
+ if (args.length == 2 && args[1].length() > 0 && args[0].length() > 0)
+ {
+ if (options.put(args[0], Double.parseDouble(args[1])) != null)
+ throw new IllegalArgumentException(args[0] + " set twice");
+ return true;
+ }
+ return false;
+ }
+
+ boolean happy()
+ {
+ return !options.isEmpty();
+ }
+
+ String shortDisplay()
+ {
+ return null;
+ }
+
+ String longDisplay()
+ {
+ return null;
+ }
+
+ List<String> multiLineDisplay()
+ {
+ return Collections.emptyList();
+ }
+
+ boolean setByUser()
+ {
+ return !options.isEmpty();
+ }
+ }
+
+
+ @Override
+ public List<? extends Option> options()
+ {
+ return Arrays.asList(ratios);
+ }
+
+ List<Pair<String, Double>> ratios()
+ {
+ List<Pair<String, Double>> ratiosOut = new ArrayList<>();
+ for (Map.Entry<String, Double> e : ratios.options.entrySet())
+ ratiosOut.add(new Pair<String, Double>(e.getKey(), e.getValue()));
+ return ratiosOut;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java
deleted file mode 100644
index bde2b10..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDataGen.java
+++ /dev/null
@@ -1,203 +0,0 @@
-package org.apache.cassandra.stress.settings;
-/*
- *
- * 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.
- *
- */
-
-
-import java.io.File;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.cassandra.stress.generatedata.*;
-
-/**
- * For selecting a data generator
- */
-class OptionDataGen extends Option
-{
-
- private static final Pattern FULL = Pattern.compile("([A-Z]+)\\(([^)]+)\\)", Pattern.CASE_INSENSITIVE);
- private static final Pattern ARGS = Pattern.compile("[^,]+");
-
- final String prefix;
- private DataGenFactory factory;
- private final DataGenFactory defaultFactory;
-
- public OptionDataGen(String prefix, String defaultSpec)
- {
- this.prefix = prefix;
- this.defaultFactory = defaultSpec == null ? null : get(defaultSpec);
- }
-
- @Override
- public boolean accept(String param)
- {
- if (!param.toLowerCase().startsWith(prefix))
- return false;
- factory = get(param.substring(prefix.length()));
- return true;
- }
-
- private static DataGenFactory get(String spec)
- {
- Matcher m = FULL.matcher(spec);
- if (!m.matches())
- throw new IllegalArgumentException("Illegal data generator specification: " + spec);
- String name = m.group(1);
- Impl impl = LOOKUP.get(name.toLowerCase());
- if (impl == null)
- throw new IllegalArgumentException("Illegal data generator type: " + name);
- List<String> params = new ArrayList<>();
- m = ARGS.matcher(m.group(2));
- while (m.find())
- params.add(m.group());
- return impl.getFactory(params);
- }
-
- public DataGenFactory get()
- {
- return factory != null ? factory : defaultFactory;
- }
-
- @Override
- public boolean happy()
- {
- return factory != null || defaultFactory != null;
- }
-
- public boolean setByUser()
- {
- return factory != null;
- }
-
- @Override
- public String shortDisplay()
- {
- return prefix + "ALG()";
- }
-
- public String longDisplay()
- {
- return shortDisplay() + ": Specify a data generator from:";
- }
-
- @Override
- public List<String> multiLineDisplay()
- {
- return Arrays.asList(
- GroupedOptions.formatMultiLine("RANDOM()", "Completely random byte generation"),
- GroupedOptions.formatMultiLine("REPEAT(<freq>)", "An MD5 hash of (opIndex % freq) combined with the column index"),
- GroupedOptions.formatMultiLine("DICT(<file>)","Random words from a dictionary; the file should be in the format \"<freq> <word>\"")
- );
- }
-
- private static final Map<String, Impl> LOOKUP;
- static
- {
- final Map<String, Impl> lookup = new HashMap<>();
- lookup.put("random", new RandomImpl());
- lookup.put("rand", new RandomImpl());
- lookup.put("rnd", new RandomImpl());
- lookup.put("repeat", new RepeatImpl());
- lookup.put("dict", new DictionaryImpl());
- lookup.put("dictionary", new DictionaryImpl());
- LOOKUP = lookup;
- }
-
- private static interface Impl
- {
- public DataGenFactory getFactory(List<String> params);
- }
-
- private static final class RandomImpl implements Impl
- {
- @Override
- public DataGenFactory getFactory(List<String> params)
- {
- if (params.size() != 0)
- throw new IllegalArgumentException("Invalid parameter list for random generator: " + params);
- return new RandomFactory();
- }
- }
-
- private static final class RepeatImpl implements Impl
- {
-
- @Override
- public DataGenFactory getFactory(List<String> params)
- {
- if (params.size() != 1)
- throw new IllegalArgumentException("Invalid parameter list for repeating generator: " + params);
- try
- {
- int repeatFrequency = Integer.parseInt(params.get(0));
- return new RepeatsFactory(repeatFrequency);
- } catch (Exception _)
- {
- throw new IllegalArgumentException("Invalid parameter list for repeating generator: " + params);
- }
- }
- }
-
- private static final class DictionaryImpl implements Impl
- {
-
- @Override
- public DataGenFactory getFactory(List<String> params)
- {
- if (params.size() != 1)
- throw new IllegalArgumentException("Invalid parameter list for dictionary generator: " + params);
- try
- {
- final File file = new File(params.get(0));
- return DataGenStringDictionary.getFactory(file);
- } catch (Exception e)
- {
- throw new IllegalArgumentException("Invalid parameter list for dictionary generator: " + params, e);
- }
- }
- }
-
- private static final class RandomFactory implements DataGenFactory
- {
- @Override
- public DataGen get()
- {
- return new DataGenBytesRandom();
- }
- }
-
- private static final class RepeatsFactory implements DataGenFactory
- {
- final int frequency;
- private RepeatsFactory(int frequency)
- {
- this.frequency = frequency;
- }
-
- @Override
- public DataGen get()
- {
- return new DataGenStringRepeats(frequency);
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java
----------------------------------------------------------------------
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 76fa0a9..70a85ae 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionDistribution.java
@@ -25,19 +25,20 @@ import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.apache.cassandra.stress.generatedata.*;
+import org.apache.cassandra.stress.generate.*;
import org.apache.commons.math3.distribution.ExponentialDistribution;
import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.commons.math3.distribution.UniformRealDistribution;
import org.apache.commons.math3.distribution.WeibullDistribution;
+import org.apache.commons.math3.random.JDKRandomGenerator;
/**
* For selecting a mathematical distribution
*/
-class OptionDistribution extends Option
+public class OptionDistribution extends Option
{
- private static final Pattern FULL = Pattern.compile("([A-Z]+)\\((.+)\\)", Pattern.CASE_INSENSITIVE);
+ private static final Pattern FULL = Pattern.compile("(~?)([A-Z]+)\\((.+)\\)", Pattern.CASE_INSENSITIVE);
private static final Pattern ARGS = Pattern.compile("[^,]+");
final String prefix;
@@ -61,20 +62,22 @@ class OptionDistribution extends Option
return true;
}
- private static DistributionFactory get(String spec)
+ public static DistributionFactory get(String spec)
{
Matcher m = FULL.matcher(spec);
if (!m.matches())
throw new IllegalArgumentException("Illegal distribution specification: " + spec);
- String name = m.group(1);
+ boolean inverse = m.group(1).equals("~");
+ String name = m.group(2);
Impl impl = LOOKUP.get(name.toLowerCase());
if (impl == null)
throw new IllegalArgumentException("Illegal distribution type: " + name);
List<String> params = new ArrayList<>();
- m = ARGS.matcher(m.group(2));
+ m = ARGS.matcher(m.group(3));
while (m.find())
params.add(m.group());
- return impl.getFactory(params);
+ DistributionFactory factory = impl.getFactory(params);
+ return inverse ? new InverseFactory(factory) : factory;
}
public DistributionFactory get()
@@ -103,6 +106,7 @@ class OptionDistribution extends Option
GroupedOptions.formatMultiLine("GAUSSIAN(min..max,mean,stdev)", "A gaussian/normal distribution, with explicitly defined mean and stdev"),
GroupedOptions.formatMultiLine("UNIFORM(min..max)", "A uniform distribution over the range [min, max]"),
GroupedOptions.formatMultiLine("FIXED(val)", "A fixed distribution, always returning the same value"),
+ "Preceding the name with ~ will invert the distribution, e.g. ~exp(1..10) will yield 10 most, instead of least, often",
"Aliases: extr, gauss, normal, norm, weibull"
);
}
@@ -142,6 +146,23 @@ class OptionDistribution extends Option
public DistributionFactory getFactory(List<String> params);
}
+ public static long parseLong(String value)
+ {
+ long multiplier = 1;
+ value = value.trim().toLowerCase();
+ switch (value.charAt(value.length() - 1))
+ {
+ case 'b':
+ multiplier *= 1000;
+ case 'm':
+ multiplier *= 1000;
+ case 'k':
+ multiplier *= 1000;
+ value = value.substring(0, value.length() - 1);
+ }
+ return Long.parseLong(value) * multiplier;
+ }
+
private static final class GaussianImpl implements Impl
{
@@ -153,8 +174,8 @@ class OptionDistribution extends Option
try
{
String[] bounds = params.get(0).split("\\.\\.+");
- final long min = Long.parseLong(bounds[0]);
- final long max = Long.parseLong(bounds[1]);
+ final long min = parseLong(bounds[0]);
+ final long max = parseLong(bounds[1]);
final double mean, stdev;
if (params.size() == 3)
{
@@ -185,8 +206,8 @@ class OptionDistribution extends Option
try
{
String[] bounds = params.get(0).split("\\.\\.+");
- final long min = Long.parseLong(bounds[0]);
- final long max = Long.parseLong(bounds[1]);
+ final long min = parseLong(bounds[0]);
+ final long max = parseLong(bounds[1]);
ExponentialDistribution findBounds = new ExponentialDistribution(1d);
// max probability should be roughly equal to accuracy of (max-min) to ensure all values are visitable,
// over entire range, but this results in overly skewed distribution, so take sqrt
@@ -209,8 +230,8 @@ class OptionDistribution extends Option
try
{
String[] bounds = params.get(0).split("\\.\\.+");
- final long min = Long.parseLong(bounds[0]);
- final long max = Long.parseLong(bounds[1]);
+ final long min = parseLong(bounds[0]);
+ final long max = parseLong(bounds[1]);
final double shape = Double.parseDouble(params.get(1));
WeibullDistribution findBounds = new WeibullDistribution(shape, 1d);
// max probability should be roughly equal to accuracy of (max-min) to ensure all values are visitable,
@@ -235,8 +256,8 @@ class OptionDistribution extends Option
try
{
String[] bounds = params.get(0).split("\\.\\.+");
- final long min = Long.parseLong(bounds[0]);
- final long max = Long.parseLong(bounds[1]);
+ final long min = parseLong(bounds[0]);
+ final long max = parseLong(bounds[1]);
return new UniformFactory(min, max);
} catch (Exception _)
{
@@ -255,7 +276,7 @@ class OptionDistribution extends Option
throw new IllegalArgumentException("Invalid parameter list for uniform distribution: " + params);
try
{
- final long key = Long.parseLong(params.get(0));
+ final long key = parseLong(params.get(0));
return new FixedFactory(key);
} catch (Exception _)
{
@@ -264,6 +285,20 @@ class OptionDistribution extends Option
}
}
+ private static final class InverseFactory implements DistributionFactory
+ {
+ final DistributionFactory wrapped;
+ private InverseFactory(DistributionFactory wrapped)
+ {
+ this.wrapped = wrapped;
+ }
+
+ public Distribution get()
+ {
+ return new DistributionInverted(wrapped.get());
+ }
+ }
+
// factories
private static final class ExpFactory implements DistributionFactory
@@ -280,7 +315,7 @@ class OptionDistribution extends Option
@Override
public Distribution get()
{
- return new DistributionOffsetApache(new ExponentialDistribution(mean), min, max);
+ return new DistributionOffsetApache(new ExponentialDistribution(new JDKRandomGenerator(), mean, ExponentialDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY), min, max);
}
}
@@ -299,7 +334,7 @@ class OptionDistribution extends Option
@Override
public Distribution get()
{
- return new DistributionOffsetApache(new WeibullDistribution(shape, scale), min, max);
+ return new DistributionOffsetApache(new WeibullDistribution(new JDKRandomGenerator(), shape, scale, WeibullDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY), min, max);
}
}
@@ -318,7 +353,7 @@ class OptionDistribution extends Option
@Override
public Distribution get()
{
- return new DistributionBoundApache(new NormalDistribution(mean, stdev), min, max);
+ return new DistributionBoundApache(new NormalDistribution(new JDKRandomGenerator(), mean, stdev, NormalDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY), min, max);
}
}
@@ -334,7 +369,7 @@ class OptionDistribution extends Option
@Override
public Distribution get()
{
- return new DistributionBoundApache(new UniformRealDistribution(min, max + 1), min, max);
+ return new DistributionBoundApache(new UniformRealDistribution(new JDKRandomGenerator(), min, max + 1), min, max);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionEnumProbabilities.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionEnumProbabilities.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionEnumProbabilities.java
new file mode 100644
index 0000000..88ebd34
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionEnumProbabilities.java
@@ -0,0 +1,62 @@
+package org.apache.cassandra.stress.settings;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math3.util.Pair;
+
+public final class OptionEnumProbabilities<T> extends OptionMulti
+{
+ final List<OptMatcher<T>> options;
+
+ public static class Opt<T>
+ {
+ final T option;
+ final String defaultValue;
+
+ public Opt(T option, String defaultValue)
+ {
+ this.option = option;
+ this.defaultValue = defaultValue;
+ }
+ }
+
+ private static final class OptMatcher<T> extends OptionSimple
+ {
+ final T opt;
+ OptMatcher(T opt, String defaultValue)
+ {
+ super(opt.toString().toLowerCase() + "=", "[0-9]+(\\.[0-9]+)?", defaultValue, "Performs this many " + opt + " operations out of total", false);
+ this.opt = opt;
+ }
+ }
+
+ public OptionEnumProbabilities(List<Opt<T>> universe, String name, String description)
+ {
+ super(name, description, false);
+ List<OptMatcher<T>> options = new ArrayList<>();
+ for (Opt<T> option : universe)
+ options.add(new OptMatcher<T>(option.option, option.defaultValue));
+ this.options = options;
+ }
+
+ @Override
+ public List<? extends Option> options()
+ {
+ return options;
+ }
+
+ List<Pair<T, Double>> ratios()
+ {
+ List<? extends Option> ratiosIn = setByUser() ? optionsSetByUser() : defaultOptions();
+ List<Pair<T, Double>> ratiosOut = new ArrayList<>();
+ for (Option opt : ratiosIn)
+ {
+ OptMatcher<T> optMatcher = (OptMatcher<T>) opt;
+ double d = Double.parseDouble(optMatcher.value());
+ ratiosOut.add(new Pair<>(optMatcher.opt, d));
+ }
+ return ratiosOut;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java
----------------------------------------------------------------------
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 60faad8..32bfc65 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionMulti.java
@@ -156,7 +156,8 @@ abstract class OptionMulti extends Option
String[] args = param.split("=");
if (args.length == 2 && args[1].length() > 0 && args[0].length() > 0)
{
- options.put(args[0], args[1]);
+ if (options.put(args[0], args[1]) != null)
+ throw new IllegalArgumentException(args[0] + " set twice");
return true;
}
return false;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionRatioDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionRatioDistribution.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionRatioDistribution.java
new file mode 100644
index 0000000..2459c20
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionRatioDistribution.java
@@ -0,0 +1,166 @@
+package org.apache.cassandra.stress.settings;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.math3.distribution.ExponentialDistribution;
+import org.apache.commons.math3.distribution.NormalDistribution;
+import org.apache.commons.math3.distribution.UniformRealDistribution;
+import org.apache.commons.math3.distribution.WeibullDistribution;
+import org.apache.commons.math3.random.JDKRandomGenerator;
+
+import org.apache.cassandra.stress.generate.Distribution;
+import org.apache.cassandra.stress.generate.DistributionBoundApache;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.DistributionFixed;
+import org.apache.cassandra.stress.generate.DistributionInverted;
+import org.apache.cassandra.stress.generate.DistributionOffsetApache;
+import org.apache.cassandra.stress.generate.RatioDistribution;
+import org.apache.cassandra.stress.generate.RatioDistributionFactory;
+
+/**
+ * For selecting a mathematical distribution
+ */
+public class OptionRatioDistribution extends Option
+{
+
+ private static final Pattern FULL = Pattern.compile("(.*)/([0-9]+[KMB]?)", Pattern.CASE_INSENSITIVE);
+
+ final OptionDistribution delegate;
+ private double divisor;
+
+ private static final RatioDistribution DEFAULT = new RatioDistribution(new DistributionFixed(1), 1);
+
+ public OptionRatioDistribution(String prefix, String defaultSpec, String description)
+ {
+ delegate = new OptionDistribution(prefix, defaultSpec, description);
+ }
+
+ @Override
+ public boolean accept(String param)
+ {
+ Matcher m = FULL.matcher(param);
+ if (!m.matches() || !delegate.accept(m.group(1)))
+ return false;
+ divisor = OptionDistribution.parseLong(m.group(2));
+ return true;
+ }
+
+ public static RatioDistributionFactory get(String spec)
+ {
+ OptionRatioDistribution opt = new OptionRatioDistribution("", "", "");
+ if (!opt.accept(spec))
+ throw new IllegalArgumentException();
+ return opt.get();
+ }
+
+ public RatioDistributionFactory get()
+ {
+ return !delegate.setByUser() ? new DefaultFactory() : new DelegateFactory(delegate.get(), divisor);
+ }
+
+ @Override
+ public boolean happy()
+ {
+ return delegate.happy();
+ }
+
+ public String longDisplay()
+ {
+ return delegate.longDisplay();
+ }
+
+ @Override
+ public List<String> multiLineDisplay()
+ {
+ return Arrays.asList(
+ GroupedOptions.formatMultiLine("EXP(min..max)/divisor", "An exponential ratio distribution over the range [min..max]/divisor"),
+ GroupedOptions.formatMultiLine("EXTREME(min..max,shape)/divisor", "An extreme value (Weibull) ratio distribution over the range [min..max]/divisor"),
+ GroupedOptions.formatMultiLine("GAUSSIAN(min..max,stdvrng)/divisor", "A gaussian/normal ratio distribution, where mean=(min+max)/2, and stdev is ((mean-min)/stdvrng)/divisor"),
+ GroupedOptions.formatMultiLine("GAUSSIAN(min..max,mean,stdev)/divisor", "A gaussian/normal ratio distribution, with explicitly defined mean and stdev"),
+ GroupedOptions.formatMultiLine("UNIFORM(min..max)/divisor", "A uniform ratio distribution over the range [min, max]/divisor"),
+ GroupedOptions.formatMultiLine("FIXED(val)/divisor", "A fixed ratio distribution, always returning the same value"),
+ "Preceding the name with ~ will invert the distribution, e.g. ~exp(1..10)/10 will yield 0.1 least, instead of most, often",
+ "Aliases: extr, gauss, normal, norm, weibull"
+ );
+ }
+
+ boolean setByUser()
+ {
+ return delegate.setByUser();
+ }
+
+ @Override
+ public String shortDisplay()
+ {
+ return delegate.shortDisplay();
+ }
+
+ // factories
+
+ private static final class DefaultFactory implements RatioDistributionFactory
+ {
+ @Override
+ public RatioDistribution get()
+ {
+ return DEFAULT;
+ }
+ }
+
+ private static final class DelegateFactory implements RatioDistributionFactory
+ {
+ final DistributionFactory delegate;
+ final double divisor;
+
+ private DelegateFactory(DistributionFactory delegate, double divisor)
+ {
+ this.delegate = delegate;
+ this.divisor = divisor;
+ }
+
+ @Override
+ public RatioDistribution get()
+ {
+ return new RatioDistribution(delegate.get(), divisor);
+ }
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object that)
+ {
+ return super.equals(that) && ((OptionRatioDistribution) that).delegate.equals(this.delegate);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java b/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java
index 9365e45..71c1ffe 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/OptionSimple.java
@@ -21,6 +21,7 @@ package org.apache.cassandra.stress.settings;
*/
+import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
@@ -30,7 +31,7 @@ import com.google.common.base.Function;
/**
* For parsing a simple (sub)option for a command/major option
*/
-class OptionSimple extends Option
+class OptionSimple extends Option implements Serializable
{
final String displayPrefix;
@@ -41,7 +42,7 @@ class OptionSimple extends Option
private final boolean required;
private String value;
- private static final class ValueMatcher implements Function<String, String>
+ private static final class ValueMatcher implements Function<String, String>, Serializable
{
final Pattern pattern;
private ValueMatcher(Pattern pattern)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
index 7e20ec6..04c2a47 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsColumn.java
@@ -23,13 +23,15 @@ package org.apache.cassandra.stress.settings;
import java.io.Serializable;
import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.cassandra.db.marshal.*;
-import org.apache.cassandra.stress.generatedata.*;
+import org.apache.cassandra.stress.generate.*;
import org.apache.cassandra.utils.ByteBufferUtil;
/**
@@ -39,17 +41,13 @@ public class SettingsColumn implements Serializable
{
public final int maxColumnsPerKey;
- public final List<ByteBuffer> names;
+ public transient final List<ByteBuffer> names;
public final List<String> namestrs;
public final String comparator;
- public final boolean useTimeUUIDComparator;
- public final int superColumns;
- public final boolean useSuperColumns;
public final boolean variableColumnCount;
public final boolean slice;
- private final DistributionFactory sizeDistribution;
- private final DistributionFactory countDistribution;
- private final DataGenFactory dataGenFactory;
+ public final DistributionFactory sizeDistribution;
+ public final DistributionFactory countDistribution;
public SettingsColumn(GroupedOptions options)
{
@@ -62,9 +60,6 @@ public class SettingsColumn implements Serializable
public SettingsColumn(Options options, NameOptions name, CountOptions count)
{
sizeDistribution = options.size.get();
- superColumns = Integer.parseInt(options.superColumns.value());
- dataGenFactory = options.generator.get();
- useSuperColumns = superColumns > 0;
{
comparator = options.comparator.value();
AbstractType parsed = null;
@@ -79,8 +74,6 @@ public class SettingsColumn implements Serializable
System.exit(1);
}
- useTimeUUIDComparator = parsed instanceof TimeUUIDType;
-
if (!(parsed instanceof TimeUUIDType || parsed instanceof AsciiType || parsed instanceof UTF8Type))
{
System.err.println("Currently supported types are: TimeUUIDType, AsciiType, UTF8Type.");
@@ -102,10 +95,13 @@ public class SettingsColumn implements Serializable
final String[] names = name.name.value().split(",");
this.names = new ArrayList<>(names.length);
- this.namestrs = Arrays.asList(names);
for (String columnName : names)
this.names.add(comparator.fromString(columnName));
+ Collections.sort(this.names, BytesType.instance);
+ this.namestrs = new ArrayList<>();
+ for (ByteBuffer columnName : this.names)
+ this.namestrs.add(comparator.getString(columnName));
final int nameCount = this.names.size();
countDistribution = new DistributionFactory()
@@ -123,23 +119,24 @@ public class SettingsColumn implements Serializable
ByteBuffer[] names = new ByteBuffer[(int) countDistribution.get().maxValue()];
String[] namestrs = new String[(int) countDistribution.get().maxValue()];
for (int i = 0 ; i < names.length ; i++)
- {
names[i] = ByteBufferUtil.bytes("C" + i);
- namestrs[i] = "C" + i;
+ Arrays.sort(names, BytesType.instance);
+ try
+ {
+ for (int i = 0 ; i < names.length ; i++)
+ namestrs[i] = ByteBufferUtil.string(names[i]);
+ }
+ catch (CharacterCodingException e)
+ {
+ throw new RuntimeException(e);
}
+
this.names = Arrays.asList(names);
this.namestrs = Arrays.asList(namestrs);
}
maxColumnsPerKey = (int) countDistribution.get().maxValue();
variableColumnCount = countDistribution.get().minValue() < maxColumnsPerKey;
- // TODO: should warn that we always slice for useTimeUUIDComparator?
- slice = options.slice.setByUser() || useTimeUUIDComparator;
- // TODO: with useTimeUUIDCOmparator, should we still try to select a random start for reads if possible?
- }
-
- public RowGen newRowGen()
- {
- return new RowGenDistributedSize(dataGenFactory.get(), countDistribution.get(), sizeDistribution.get());
+ slice = options.slice.setByUser();
}
// Option Declarations
@@ -150,7 +147,6 @@ public class SettingsColumn implements Serializable
final OptionSimple comparator = new OptionSimple("comparator=", "TimeUUIDType|AsciiType|UTF8Type", "AsciiType", "Column Comparator to use", false);
final OptionSimple slice = new OptionSimple("slice", "", null, "If set, range slices will be used for reads, otherwise a names query will be", false);
final OptionDistribution size = new OptionDistribution("size=", "FIXED(34)", "Cell size distribution");
- final OptionDataGen generator = new OptionDataGen("data=", "REPEAT(50)");
}
private static final class NameOptions extends Options
@@ -160,7 +156,7 @@ public class SettingsColumn implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(name, slice, superColumns, comparator, size, generator);
+ return Arrays.asList(name, slice, superColumns, comparator, size);
}
}
@@ -171,7 +167,7 @@ public class SettingsColumn implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(count, slice, superColumns, comparator, size, generator);
+ return Arrays.asList(count, slice, superColumns, comparator, size);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
index b491707..032f00c 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommand.java
@@ -26,23 +26,24 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import org.apache.cassandra.stress.generatedata.DistributionFactory;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
import org.apache.cassandra.thrift.ConsistencyLevel;
// Generic command settings - common to read/write/etc
-public class SettingsCommand implements Serializable
+public abstract class SettingsCommand implements Serializable
{
public final Command type;
public final long count;
public final int tries;
public final boolean ignoreErrors;
+ public final boolean noWarmup;
public final ConsistencyLevel consistencyLevel;
public final double targetUncertainty;
public final int minimumUncertaintyMeasurements;
public final int maximumUncertaintyMeasurements;
- public final DistributionFactory add;
- public final int keysAtOnce;
+
+ public abstract OpDistributionFactory getFactory(StressSettings settings);
public SettingsCommand(Command type, GroupedOptions options)
{
@@ -58,8 +59,7 @@ public class SettingsCommand implements Serializable
this.tries = Math.max(1, Integer.parseInt(options.retries.value()) + 1);
this.ignoreErrors = options.ignoreErrors.setByUser();
this.consistencyLevel = ConsistencyLevel.valueOf(options.consistencyLevel.value().toUpperCase());
- this.keysAtOnce = Integer.parseInt(options.atOnce.value());
- this.add = options.add.get();
+ this.noWarmup = options.noWarmup.setByUser();
if (count != null)
{
this.count = Long.parseLong(count.count.value());
@@ -82,8 +82,8 @@ public class SettingsCommand implements Serializable
{
final OptionSimple retries = new OptionSimple("tries=", "[0-9]+", "9", "Number of tries to perform for each operation before failing", false);
final OptionSimple ignoreErrors = new OptionSimple("ignore_errors", "", null, "Do not print/log errors", false);
+ final OptionSimple noWarmup = new OptionSimple("no_warmup", "", null, "Do not warmup the process", false);
final OptionSimple consistencyLevel = new OptionSimple("cl=", "ONE|QUORUM|LOCAL_QUORUM|EACH_QUORUM|ALL|ANY", "ONE", "Consistency level to use", false);
- final OptionDistribution add = new OptionDistribution("add=", "fixed(1)", "Distribution of value of counter increments");
final OptionSimple atOnce = new OptionSimple("at-once=", "[0-9]+", "1000", "Number of keys per operation for multiget", false);
}
@@ -93,7 +93,7 @@ public class SettingsCommand implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(count, retries, ignoreErrors, consistencyLevel, add, atOnce);
+ return Arrays.asList(count, retries, noWarmup, ignoreErrors, consistencyLevel, atOnce);
}
}
@@ -105,7 +105,7 @@ public class SettingsCommand implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(uncertainty, minMeasurements, maxMeasurements, retries, ignoreErrors, consistencyLevel, add, atOnce);
+ return Arrays.asList(uncertainty, minMeasurements, maxMeasurements, retries, noWarmup, ignoreErrors, consistencyLevel, atOnce);
}
}
@@ -127,48 +127,16 @@ public class SettingsCommand implements Serializable
switch (cmd.category)
{
case BASIC:
- case MULTI:
- return build(cmd, params);
+ return SettingsCommandPreDefined.build(cmd, params);
case MIXED:
- return SettingsCommandMixed.build(params);
+ return SettingsCommandPreDefinedMixed.build(params);
+ case USER:
+ return SettingsCommandUser.build(params);
}
}
}
return null;
}
- static SettingsCommand build(Command type, String[] params)
- {
- GroupedOptions options = GroupedOptions.select(params, new Count(), new Uncertainty());
- if (options == null)
- {
- printHelp(type);
- System.out.println("Invalid " + type + " options provided, see output for valid options");
- System.exit(1);
- }
- return new SettingsCommand(type, options);
- }
-
- static void printHelp(Command type)
- {
- printHelp(type.toString().toLowerCase());
- }
-
- static void printHelp(String type)
- {
- GroupedOptions.printOptions(System.out, type.toLowerCase(), new Uncertainty(), new Count());
- }
-
- static Runnable helpPrinter(final Command type)
- {
- return new Runnable()
- {
- @Override
- public void run()
- {
- printHelp(type);
- }
- };
- }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMixed.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMixed.java
deleted file mode 100644
index 3f16425..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandMixed.java
+++ /dev/null
@@ -1,207 +0,0 @@
-package org.apache.cassandra.stress.settings;
-/*
- *
- * 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.
- *
- */
-
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.cassandra.stress.generatedata.Distribution;
-import org.apache.cassandra.stress.generatedata.DistributionFactory;
-
-import org.apache.commons.math3.distribution.EnumeratedDistribution;
-import org.apache.commons.math3.util.Pair;
-
-// Settings unique to the mixed command type
-public class SettingsCommandMixed extends SettingsCommand
-{
-
- // Ratios for selecting commands - index for each Command, NaN indicates the command is not requested
- private final List<Pair<Command, Double>> ratios;
- private final DistributionFactory clustering;
-
- public SettingsCommandMixed(Options options)
- {
- super(Command.MIXED, options.parent);
-
- clustering = options.clustering.get();
- ratios = options.probabilities.ratios();
- if (ratios.size() == 0)
- throw new IllegalArgumentException("Must specify at least one command with a non-zero ratio");
- }
-
- public List<Command> getCommands()
- {
- final List<Command> r = new ArrayList<>();
- for (Pair<Command, Double> p : ratios)
- r.add(p.getFirst());
- return r;
- }
-
- public CommandSelector selector()
- {
- return new CommandSelector(ratios, clustering.get());
- }
-
- // Class for randomly selecting the next command type
-
- public static final class CommandSelector
- {
-
- final EnumeratedDistribution<Command> selector;
- final Distribution count;
- private Command cur;
- private long remaining;
-
- public CommandSelector(List<Pair<Command, Double>> ratios, Distribution count)
- {
- selector = new EnumeratedDistribution<>(ratios);
- this.count = count;
- }
-
- public Command next()
- {
- while (remaining == 0)
- {
- remaining = count.next();
- cur = selector.sample();
- }
- remaining--;
- return cur;
- }
- }
-
- // Option Declarations
-
- static final class Probabilities extends OptionMulti
- {
- // entry for each in Command.values()
- final OptionSimple[] ratios;
- final List<OptionSimple> grouping;
-
- public Probabilities()
- {
- super("ratio", "Specify the ratios for operations to perform; e.g. (reads=2,writes=1) will perform 2 reads for each write", false);
- OptionSimple[] ratios = new OptionSimple[Command.values().length];
- List<OptionSimple> grouping = new ArrayList<>();
- for (Command command : Command.values())
- {
- if (command.category == null)
- continue;
- String defaultValue;
- switch (command)
- {
- case MIXED:
- continue;
- case READ:
- case WRITE:
- defaultValue = "1";
- break;
- default:
- defaultValue = null;
- }
- OptionSimple ratio = new OptionSimple(command.toString().toLowerCase() +
- "=", "[0-9]+(\\.[0-9]+)?", defaultValue, "Performs this many " + command + " operations out of total", false);
- ratios[command.ordinal()] = ratio;
- grouping.add(ratio);
- }
- this.grouping = grouping;
- this.ratios = ratios;
- }
-
- @Override
- public List<? extends Option> options()
- {
- return grouping;
- }
-
- List<Pair<Command, Double>> ratios()
- {
- List<? extends Option> ratiosIn = setByUser() ? optionsSetByUser() : defaultOptions();
- List<Pair<Command, Double>> ratiosOut = new ArrayList<>();
- for (Option opt : ratiosIn)
- {
- OptionSimple ratioIn = (OptionSimple) opt;
- Command command = Command.get(ratioIn.displayPrefix.substring(0, ratioIn.displayPrefix.length() - 1));
- double d = Double.parseDouble(ratioIn.value());
- ratiosOut.add(new Pair<>(command, d));
- }
- return ratiosOut;
- }
- }
-
- static final class Options extends GroupedOptions
- {
- final SettingsCommand.Options parent;
- protected Options(SettingsCommand.Options parent)
- {
- this.parent = parent;
- }
- final OptionDistribution clustering = new OptionDistribution("clustering=", "GAUSSIAN(1..10)", "Distribution clustering runs of operations of the same kind");
- final Probabilities probabilities = new Probabilities();
-
- @Override
- public List<? extends Option> options()
- {
- final List<Option> options = new ArrayList<>();
- options.add(clustering);
- options.add(probabilities);
- options.addAll(parent.options());
- return options;
- }
-
- }
-
- // CLI utility methods
-
- public static SettingsCommandMixed build(String[] params)
- {
- GroupedOptions options = GroupedOptions.select(params,
- new Options(new SettingsCommand.Uncertainty()),
- new Options(new SettingsCommand.Count()));
- if (options == null)
- {
- printHelp();
- System.out.println("Invalid MIXED options provided, see output for valid options");
- System.exit(1);
- }
- return new SettingsCommandMixed((Options) options);
- }
-
- public static void printHelp()
- {
- GroupedOptions.printOptions(System.out, "mixed",
- new Options(new SettingsCommand.Uncertainty()),
- new Options(new SettingsCommand.Count()));
- }
-
- public static Runnable helpPrinter()
- {
- return new Runnable()
- {
- @Override
- public void run()
- {
- printHelp();
- }
- };
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
new file mode 100644
index 0000000..ac113d1
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
@@ -0,0 +1,145 @@
+package org.apache.cassandra.stress.settings;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.generate.values.Bytes;
+import org.apache.cassandra.stress.generate.values.Generator;
+import org.apache.cassandra.stress.generate.values.GeneratorConfig;
+import org.apache.cassandra.stress.generate.values.HexBytes;
+import org.apache.cassandra.stress.operations.FixedOpDistribution;
+import org.apache.cassandra.stress.operations.OpDistribution;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
+import org.apache.cassandra.stress.operations.predefined.PredefinedOperation;
+import org.apache.cassandra.stress.util.Timer;
+
+// Settings unique to the mixed command type
+public class SettingsCommandPreDefined extends SettingsCommand
+{
+
+ public final DistributionFactory add;
+
+ public OpDistributionFactory getFactory(final StressSettings settings)
+ {
+ return new OpDistributionFactory()
+ {
+ public OpDistribution get(Timer timer)
+ {
+ return new FixedOpDistribution(PredefinedOperation.operation(type, timer, newGenerator(settings), settings, add));
+ }
+
+ public String desc()
+ {
+ return type.toString();
+ }
+
+ public Iterable<OpDistributionFactory> each()
+ {
+ return Collections.<OpDistributionFactory>singleton(this);
+ }
+ };
+ }
+
+ PartitionGenerator newGenerator(StressSettings settings)
+ {
+ List<String> names = settings.columns.namestrs;
+ List<Generator> partitionKey = Collections.<Generator>singletonList(new HexBytes("key",
+ new GeneratorConfig("randomstrkey", null,
+ OptionDistribution.get("fixed(" + settings.keys.keySize + ")"), null)));
+
+ List<Generator> columns = new ArrayList<>();
+ for (int i = 0 ; i < settings.columns.maxColumnsPerKey ; i++)
+ columns.add(new Bytes(names.get(i), new GeneratorConfig("randomstr" + names.get(i), null, settings.columns.sizeDistribution, null)));
+ return new PartitionGenerator(partitionKey, Collections.<Generator>emptyList(), columns);
+ }
+
+ public SettingsCommandPreDefined(Command type, Options options)
+ {
+ super(type, options.parent);
+ add = options.add.get();
+ }
+
+ // Option Declarations
+
+ static class Options extends GroupedOptions
+ {
+ final SettingsCommand.Options parent;
+ protected Options(SettingsCommand.Options parent)
+ {
+ this.parent = parent;
+ }
+ final OptionDistribution add = new OptionDistribution("add=", "fixed(1)", "Distribution of value of counter increments");
+
+ @Override
+ public List<? extends Option> options()
+ {
+ final List<Option> options = new ArrayList<>();
+ options.addAll(parent.options());
+ options.add(add);
+ return options;
+ }
+
+ }
+
+ // CLI utility methods
+
+ public static SettingsCommandPreDefined build(Command type, String[] params)
+ {
+ GroupedOptions options = GroupedOptions.select(params,
+ new Options(new Uncertainty()),
+ new Options(new Count()));
+ if (options == null)
+ {
+ printHelp(type);
+ System.out.println("Invalid " + type + " options provided, see output for valid options");
+ System.exit(1);
+ }
+ return new SettingsCommandPreDefined(type, (Options) options);
+ }
+
+ static void printHelp(Command type)
+ {
+ printHelp(type.toString().toLowerCase());
+ }
+
+ static void printHelp(String type)
+ {
+ GroupedOptions.printOptions(System.out, type.toLowerCase(), new Uncertainty(), new Count());
+ }
+
+ static Runnable helpPrinter(final Command type)
+ {
+ return new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ printHelp(type);
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
new file mode 100644
index 0000000..e5d4f80
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java
@@ -0,0 +1,151 @@
+package org.apache.cassandra.stress.settings;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
+import org.apache.cassandra.stress.operations.SampledOpDistributionFactory;
+import org.apache.cassandra.stress.operations.predefined.PredefinedOperation;
+import org.apache.cassandra.stress.util.Timer;
+
+import org.apache.commons.math3.util.Pair;
+
+// Settings unique to the mixed command type
+public class SettingsCommandPreDefinedMixed extends SettingsCommandPreDefined
+{
+
+ // Ratios for selecting commands - index for each Command, NaN indicates the command is not requested
+ private final List<Pair<Command, Double>> ratios;
+ private final DistributionFactory clustering;
+
+ public SettingsCommandPreDefinedMixed(Options options)
+ {
+ super(Command.MIXED, options);
+
+ clustering = options.clustering.get();
+ ratios = options.probabilities.ratios();
+ if (ratios.size() == 0)
+ throw new IllegalArgumentException("Must specify at least one command with a non-zero ratio");
+ }
+
+ public OpDistributionFactory getFactory(final StressSettings settings)
+ {
+ return new SampledOpDistributionFactory<Command>(ratios, clustering)
+ {
+ protected Operation get(Timer timer, PartitionGenerator generator, Command key)
+ {
+ return PredefinedOperation.operation(key, timer, generator, settings, add);
+ }
+
+ protected PartitionGenerator newGenerator()
+ {
+ return SettingsCommandPreDefinedMixed.this.newGenerator(settings);
+ }
+ };
+ }
+
+ // Option Declarations
+
+ static class Options extends SettingsCommandPreDefined.Options
+ {
+ static List<OptionEnumProbabilities.Opt<Command>> probabilityOptions = new ArrayList<>();
+ static
+ {
+ for (Command command : Command.values())
+ {
+ if (command.category == null)
+ continue;
+ String defaultValue;
+ switch (command)
+ {
+ case MIXED:
+ continue;
+ case READ:
+ case WRITE:
+ defaultValue = "1";
+ break;
+ default:
+ defaultValue = null;
+ }
+ probabilityOptions.add(new OptionEnumProbabilities.Opt<>(command, defaultValue));
+ }
+ }
+
+ protected Options(SettingsCommand.Options parent)
+ {
+ super(parent);
+ }
+ final OptionDistribution clustering = new OptionDistribution("clustering=", "GAUSSIAN(1..10)", "Distribution clustering runs of operations of the same kind");
+ final OptionEnumProbabilities probabilities = new OptionEnumProbabilities<>(probabilityOptions, "ratio", "Specify the ratios for operations to perform; e.g. (read=2,write=1) will perform 2 reads for each write");
+
+ @Override
+ public List<? extends Option> options()
+ {
+ final List<Option> options = new ArrayList<>();
+ options.add(clustering);
+ options.add(probabilities);
+ options.addAll(super.options());
+ return options;
+ }
+
+ }
+
+ // CLI utility methods
+
+ public static SettingsCommandPreDefinedMixed build(String[] params)
+ {
+ GroupedOptions options = GroupedOptions.select(params,
+ new Options(new SettingsCommand.Uncertainty()),
+ new Options(new SettingsCommand.Count()));
+ if (options == null)
+ {
+ printHelp();
+ System.out.println("Invalid MIXED options provided, see output for valid options");
+ System.exit(1);
+ }
+ return new SettingsCommandPreDefinedMixed((Options) options);
+ }
+
+ public static void printHelp()
+ {
+ GroupedOptions.printOptions(System.out, "mixed",
+ new Options(new SettingsCommand.Uncertainty()),
+ new Options(new SettingsCommand.Count()));
+ }
+
+ public static Runnable helpPrinter()
+ {
+ return new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ printHelp();
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
new file mode 100644
index 0000000..f36296e
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java
@@ -0,0 +1,135 @@
+package org.apache.cassandra.stress.settings;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math3.util.Pair;
+
+import org.apache.cassandra.stress.Operation;
+import org.apache.cassandra.stress.StressProfile;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.PartitionGenerator;
+import org.apache.cassandra.stress.operations.OpDistributionFactory;
+import org.apache.cassandra.stress.operations.SampledOpDistributionFactory;
+import org.apache.cassandra.stress.util.Timer;
+
+// Settings unique to the mixed command type
+public class SettingsCommandUser extends SettingsCommand
+{
+
+ // Ratios for selecting commands - index for each Command, NaN indicates the command is not requested
+ private final List<Pair<String, Double>> ratios;
+ private final DistributionFactory clustering;
+ public final StressProfile profile;
+
+ public SettingsCommandUser(Options options)
+ {
+ super(Command.USER, options.parent);
+
+ clustering = options.clustering.get();
+ ratios = options.ops.ratios();
+ profile = StressProfile.load(new File(options.profile.value()));
+
+ if (ratios.size() == 0)
+ throw new IllegalArgumentException("Must specify at least one command with a non-zero ratio");
+ }
+
+ public OpDistributionFactory getFactory(final StressSettings settings)
+ {
+ return new SampledOpDistributionFactory<String>(ratios, clustering)
+ {
+ protected Operation get(Timer timer, PartitionGenerator generator, String key)
+ {
+ if (key.equalsIgnoreCase("insert"))
+ return profile.getInsert(timer, generator, settings);
+ return profile.getQuery(key, timer, generator, settings);
+ }
+
+ protected PartitionGenerator newGenerator()
+ {
+ return profile.newGenerator(settings);
+ }
+ };
+ }
+
+ static final class Options extends GroupedOptions
+ {
+ final SettingsCommand.Options parent;
+ protected Options(SettingsCommand.Options parent)
+ {
+ this.parent = parent;
+ }
+ final OptionDistribution clustering = new OptionDistribution("clustering=", "GAUSSIAN(1..10)", "Distribution clustering runs of operations of the same kind");
+ final OptionSimple profile = new OptionSimple("profile=", ".*", null, "Specify the path to a yaml cql3 profile", false);
+ final OptionAnyProbabilities ops = new OptionAnyProbabilities("ops", "Specify the ratios for inserts/queries to perform; e.g. ops(insert=2,<query1>=1) will perform 2 inserts for each query1");
+
+ @Override
+ public List<? extends Option> options()
+ {
+ final List<Option> options = new ArrayList<>();
+ options.add(clustering);
+ options.add(ops);
+ options.add(profile);
+ options.addAll(parent.options());
+ return options;
+ }
+
+ }
+
+ // CLI utility methods
+
+ public static SettingsCommandUser build(String[] params)
+ {
+ GroupedOptions options = GroupedOptions.select(params,
+ new Options(new Uncertainty()),
+ new Options(new Count()));
+ if (options == null)
+ {
+ printHelp();
+ System.out.println("Invalid USER options provided, see output for valid options");
+ System.exit(1);
+ }
+ return new SettingsCommandUser((Options) options);
+ }
+
+ public static void printHelp()
+ {
+ GroupedOptions.printOptions(System.out, "user",
+ new Options(new Uncertainty()),
+ new Options(new Count()));
+ }
+
+ public static Runnable helpPrinter()
+ {
+ return new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ printHelp();
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java
index ab489be..017b106 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsKey.java
@@ -26,23 +26,25 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import org.apache.cassandra.stress.generatedata.DataGenHexFromDistribution;
-import org.apache.cassandra.stress.generatedata.DataGenHexFromOpIndex;
-import org.apache.cassandra.stress.generatedata.DistributionFactory;
-import org.apache.cassandra.stress.generatedata.KeyGen;
+import org.apache.cassandra.stress.generate.DistributionFactory;
+import org.apache.cassandra.stress.generate.SeedGenerator;
+import org.apache.cassandra.stress.generate.SeedRandomGenerator;
+import org.apache.cassandra.stress.generate.SeedSeriesGenerator;
// Settings for key generation
public class SettingsKey implements Serializable
{
- private final int keySize;
+ final int keySize;
private final DistributionFactory distribution;
+ private final DistributionFactory clustering;
private final long[] range;
public SettingsKey(DistributionOptions options)
{
this.keySize = Integer.parseInt(options.size.value());
this.distribution = options.dist.get();
+ this.clustering = options.clustering.get();
this.range = null;
}
@@ -50,8 +52,9 @@ public class SettingsKey implements Serializable
{
this.keySize = Integer.parseInt(options.size.value());
this.distribution = null;
+ this.clustering = null;
String[] bounds = options.populate.value().split("\\.\\.+");
- this.range = new long[] { Long.parseLong(bounds[0]), Long.parseLong(bounds[1]) };
+ this.range = new long[] { OptionDistribution.parseLong(bounds[0]), OptionDistribution.parseLong(bounds[1]) };
}
// Option Declarations
@@ -59,6 +62,7 @@ public class SettingsKey implements Serializable
private static final class DistributionOptions extends GroupedOptions
{
final OptionDistribution dist;
+ final OptionDistribution clustering = new OptionDistribution("cluster=", "fixed(1)", "Keys are clustered in adjacent value runs of this size");
final OptionSimple size = new OptionSimple("size=", "[0-9]+", "10", "Key size in bytes", false);
public DistributionOptions(String defaultLimit)
@@ -69,7 +73,7 @@ public class SettingsKey implements Serializable
@Override
public List<? extends Option> options()
{
- return Arrays.asList(dist, size);
+ return Arrays.asList(dist, size, clustering);
}
}
@@ -80,7 +84,7 @@ public class SettingsKey implements Serializable
public PopulateOptions(String defaultLimit)
{
- populate = new OptionSimple("populate=", "[0-9]+\\.\\.+[0-9]+",
+ populate = new OptionSimple("populate=", "[0-9]+\\.\\.+[0-9]+[MBK]?",
"1.." + defaultLimit,
"Populate all keys in sequence", true);
}
@@ -92,12 +96,9 @@ public class SettingsKey implements Serializable
}
}
- public KeyGen newKeyGen()
+ public SeedGenerator newSeedGenerator()
{
- return new KeyGen(range == null
- ? new DataGenHexFromDistribution(distribution.get())
- : new DataGenHexFromOpIndex(range[0], range[1]),
- keySize);
+ return range == null ? new SeedRandomGenerator(distribution.get(), clustering.get()) : new SeedSeriesGenerator(range[0], range[1]);
}
// CLI Utility Methods
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java
index 8a5975f..5735f9d 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMisc.java
@@ -27,7 +27,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import org.apache.cassandra.stress.generatedata.Distribution;
+import org.apache.cassandra.stress.generate.Distribution;
public class SettingsMisc implements Serializable
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
index 95c3da3..1aa745c 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsMode.java
@@ -161,8 +161,10 @@ public class SettingsMode implements Serializable
String[] params = clArgs.remove("-mode");
if (params == null)
{
- ThriftOptions opts = new ThriftOptions();
- opts.smart.accept("smart");
+ Cql3NativeOptions opts = new Cql3NativeOptions();
+ opts.accept("cql3");
+ opts.accept("native");
+ opts.accept("prepared");
return new SettingsMode(opts);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
index ffafb67..5fb2bb2 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSchema.java
@@ -25,40 +25,51 @@ import java.nio.ByteBuffer;
import java.util.*;
import org.apache.cassandra.thrift.*;
+import org.apache.cassandra.thrift.ConsistencyLevel;
import org.apache.cassandra.utils.ByteBufferUtil;
public class SettingsSchema implements Serializable
{
- public static final String DEFAULT_COMPARATOR = "AsciiType";
public static final String DEFAULT_VALIDATOR = "BytesType";
private final String replicationStrategy;
private final Map<String, String> replicationStrategyOptions;
- private final IndexType indexType;
private final String compression;
private final String compactionStrategy;
private final Map<String, String> compactionStrategyOptions;
public final String keyspace;
- public SettingsSchema(Options options)
+ public SettingsSchema(Options options, SettingsCommand command)
{
+ if (command instanceof SettingsCommandUser)
+ {
+ if (options.compaction.setByUser() || options.keyspace.setByUser() || options.compression.setByUser() || options.replication.setByUser())
+ throw new IllegalArgumentException("Cannot provide command line schema settings if a user profile is provided");
+
+ keyspace = ((SettingsCommandUser) command).profile.keyspaceName;
+ }
+ else
+ keyspace = options.keyspace.value();
+
replicationStrategy = options.replication.getStrategy();
replicationStrategyOptions = options.replication.getOptions();
- if (options.index.setByUser())
- indexType = IndexType.valueOf(options.index.value().toUpperCase());
- else
- indexType = null;
compression = options.compression.value();
compactionStrategy = options.compaction.getStrategy();
compactionStrategyOptions = options.compaction.getOptions();
- keyspace = options.keyspace.value();
}
public void createKeySpaces(StressSettings settings)
{
- createKeySpacesThrift(settings);
+ if (!(settings.command instanceof SettingsCommandUser))
+ {
+ createKeySpacesThrift(settings);
+ }
+ else
+ {
+ ((SettingsCommandUser) settings.command).profile.maybeCreateSchema(settings);
+ }
}
@@ -71,7 +82,7 @@ public class SettingsSchema implements Serializable
// column family for standard columns
CfDef standardCfDef = new CfDef(keyspace, "Standard1");
- Map<String, String> compressionOptions = new HashMap<String, String>();
+ Map<String, String> compressionOptions = new HashMap<>();
if (compression != null)
compressionOptions.put("sstable_compression", compression);
@@ -80,28 +91,8 @@ public class SettingsSchema implements Serializable
.setDefault_validation_class(DEFAULT_VALIDATOR)
.setCompression_options(compressionOptions);
- if (!settings.columns.useTimeUUIDComparator)
- {
- for (int i = 0; i < settings.columns.maxColumnsPerKey; i++)
- {
- standardCfDef.addToColumn_metadata(new ColumnDef(ByteBufferUtil.bytes("C" + i), "BytesType"));
- }
- }
-
- if (indexType != null)
- {
- ColumnDef standardColumn = new ColumnDef(ByteBufferUtil.bytes("C1"), "BytesType");
- standardColumn.setIndex_type(indexType).setIndex_name("Idx1");
- standardCfDef.setColumn_metadata(Arrays.asList(standardColumn));
- }
-
- // column family with super columns
- CfDef superCfDef = new CfDef(keyspace, "Super1")
- .setColumn_type("Super");
- superCfDef.setComparator_type(DEFAULT_COMPARATOR)
- .setSubcomparator_type(comparator)
- .setDefault_validation_class(DEFAULT_VALIDATOR)
- .setCompression_options(compressionOptions);
+ for (int i = 0; i < settings.columns.names.size(); i++)
+ standardCfDef.addToColumn_metadata(new ColumnDef(settings.columns.names.get(i), "BytesType"));
// column family for standard counters
CfDef counterCfDef = new CfDef(keyspace, "Counter1")
@@ -109,13 +100,6 @@ public class SettingsSchema implements Serializable
.setDefault_validation_class("CounterColumnType")
.setCompression_options(compressionOptions);
- // column family with counter super columns
- CfDef counterSuperCfDef = new CfDef(keyspace, "SuperCounter1")
- .setComparator_type(comparator)
- .setDefault_validation_class("CounterColumnType")
- .setColumn_type("Super")
- .setCompression_options(compressionOptions);
-
ksdef.setName(keyspace);
ksdef.setStrategy_class(replicationStrategy);
@@ -127,19 +111,15 @@ public class SettingsSchema implements Serializable
if (compactionStrategy != null)
{
standardCfDef.setCompaction_strategy(compactionStrategy);
- superCfDef.setCompaction_strategy(compactionStrategy);
counterCfDef.setCompaction_strategy(compactionStrategy);
- counterSuperCfDef.setCompaction_strategy(compactionStrategy);
if (!compactionStrategyOptions.isEmpty())
{
standardCfDef.setCompaction_strategy_options(compactionStrategyOptions);
- superCfDef.setCompaction_strategy_options(compactionStrategyOptions);
counterCfDef.setCompaction_strategy_options(compactionStrategyOptions);
- counterSuperCfDef.setCompaction_strategy_options(compactionStrategyOptions);
}
}
- ksdef.setCf_defs(new ArrayList<>(Arrays.asList(standardCfDef, superCfDef, counterCfDef, counterSuperCfDef)));
+ ksdef.setCf_defs(new ArrayList<>(Arrays.asList(standardCfDef, counterCfDef)));
Cassandra.Client client = settings.getRawThriftClient(false);
@@ -191,24 +171,23 @@ public class SettingsSchema implements Serializable
{
final OptionReplication replication = new OptionReplication();
final OptionCompaction compaction = new OptionCompaction();
- final OptionSimple index = new OptionSimple("index=", "KEYS|CUSTOM|COMPOSITES", null, "Type of index to create on needed column families (KEYS)", false);
final OptionSimple keyspace = new OptionSimple("keyspace=", ".*", "Keyspace1", "The keyspace name to use", false);
final OptionSimple compression = new OptionSimple("compression=", ".*", null, "Specify the compression to use for sstable, default:no compression", false);
@Override
public List<? extends Option> options()
{
- return Arrays.asList(replication, index, keyspace, compaction, compression);
+ return Arrays.asList(replication, keyspace, compaction, compression);
}
}
// CLI Utility Methods
- public static SettingsSchema get(Map<String, String[]> clArgs)
+ public static SettingsSchema get(Map<String, String[]> clArgs, SettingsCommand command)
{
String[] params = clArgs.remove("-schema");
if (params == null)
- return new SettingsSchema(new Options());
+ return new SettingsSchema(new Options(), command);
GroupedOptions options = GroupedOptions.select(params, new Options());
if (options == null)
@@ -217,7 +196,7 @@ public class SettingsSchema implements Serializable
System.out.println("Invalid -schema options provided, see output for valid options");
System.exit(1);
}
- return new SettingsSchema((Options) options);
+ return new SettingsSchema((Options) options, command);
}
public static void printHelp()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
index 396095d..8b0ef6a 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsTransport.java
@@ -111,7 +111,7 @@ public class SettingsTransport implements Serializable
// Option Declarations
- static class TOptions extends GroupedOptions
+ static class TOptions extends GroupedOptions implements Serializable
{
final OptionSimple factory = new OptionSimple("factory=", ".*", TFramedTransportFactory.class.getName(), "Fully-qualified ITransportFactory class name for creating a connection. Note: For Thrift over SSL, use org.apache.cassandra.thrift.SSLTransportFactory.", false);
final OptionSimple trustStore = new OptionSimple("truststore=", ".*", null, "SSL: full path to truststore", false);
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
index a1d68b4..ab57289 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
@@ -29,6 +29,7 @@ import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.stress.util.JavaDriverClient;
import org.apache.cassandra.stress.util.SimpleThriftClient;
import org.apache.cassandra.stress.util.SmartThriftClient;
+import org.apache.cassandra.stress.util.ThriftClient;
import org.apache.cassandra.thrift.Cassandra;
import org.apache.cassandra.thrift.InvalidRequestException;
import org.apache.cassandra.transport.SimpleClient;
@@ -37,7 +38,6 @@ import org.apache.thrift.transport.TTransport;
public class StressSettings implements Serializable
{
-
public final SettingsCommand command;
public final SettingsRate rate;
public final SettingsKey keys;
@@ -65,7 +65,24 @@ public class StressSettings implements Serializable
this.sendToDaemon = sendToDaemon;
}
- public SmartThriftClient getSmartThriftClient()
+ private SmartThriftClient tclient;
+
+ /**
+ * Thrift client connection
+ * @return cassandra client connection
+ */
+ public synchronized ThriftClient getThriftClient()
+ {
+ if (mode.api != ConnectionAPI.THRIFT_SMART)
+ return getSimpleThriftClient();
+
+ if (tclient == null)
+ tclient = getSmartThriftClient();
+
+ return tclient;
+ }
+
+ private SmartThriftClient getSmartThriftClient()
{
Metadata metadata = getJavaDriverClient().getCluster().getMetadata();
return new SmartThriftClient(this, schema.keyspace, metadata);
@@ -75,7 +92,7 @@ public class StressSettings implements Serializable
* Thrift client connection
* @return cassandra client connection
*/
- public SimpleThriftClient getThriftClient()
+ private SimpleThriftClient getSimpleThriftClient()
{
return new SimpleThriftClient(getRawThriftClient(node.randomNode(), true));
}
@@ -139,6 +156,11 @@ public class StressSettings implements Serializable
public JavaDriverClient getJavaDriverClient()
{
+ return getJavaDriverClient(true);
+ }
+
+ public JavaDriverClient getJavaDriverClient(boolean setKeyspace)
+ {
if (client != null)
return client;
@@ -153,7 +175,9 @@ public class StressSettings implements Serializable
EncryptionOptions.ClientEncryptionOptions encOptions = transport.getEncryptionOptions();
JavaDriverClient c = new JavaDriverClient(currentNode, port.nativePort, encOptions);
c.connect(mode.compression());
- c.execute("USE \"" + schema.keyspace + "\";", org.apache.cassandra.db.ConsistencyLevel.ONE);
+ if (setKeyspace)
+ c.execute("USE \"" + schema.keyspace + "\";", org.apache.cassandra.db.ConsistencyLevel.ONE);
+
return client = c;
}
}
@@ -165,7 +189,7 @@ public class StressSettings implements Serializable
public void maybeCreateKeyspaces()
{
- if (command.type == Command.WRITE || command.type == Command.COUNTER_WRITE)
+ if (command.type == Command.WRITE || command.type == Command.COUNTER_WRITE || command.type == Command.USER)
schema.createKeySpaces(this);
}
@@ -202,7 +226,7 @@ public class StressSettings implements Serializable
SettingsLog log = SettingsLog.get(clArgs);
SettingsMode mode = SettingsMode.get(clArgs);
SettingsNode node = SettingsNode.get(clArgs);
- SettingsSchema schema = SettingsSchema.get(clArgs);
+ SettingsSchema schema = SettingsSchema.get(clArgs, command);
SettingsTransport transport = SettingsTransport.get(clArgs);
if (!clArgs.isEmpty())
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/settings/ValidationType.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/ValidationType.java b/tools/stress/src/org/apache/cassandra/stress/settings/ValidationType.java
new file mode 100644
index 0000000..c22242d
--- /dev/null
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/ValidationType.java
@@ -0,0 +1,8 @@
+package org.apache.cassandra.stress.settings;
+
+public enum ValidationType
+{
+
+ NOT_FAIL, NON_ZERO, SUBSET, EQUAL
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/75364296/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java b/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java
index f216c05..c901461 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/JavaDriverClient.java
@@ -18,6 +18,8 @@
package org.apache.cassandra.stress.util;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import javax.net.ssl.SSLContext;
import com.datastax.driver.core.*;
@@ -40,6 +42,8 @@ public class JavaDriverClient
private Cluster cluster;
private Session session;
+ private static final ConcurrentMap<String, PreparedStatement> stmts = new ConcurrentHashMap<>();
+
public JavaDriverClient(String host, int port)
{
this(host, port, new EncryptionOptions.ClientEncryptionOptions());
@@ -54,7 +58,18 @@ public class JavaDriverClient
public PreparedStatement prepare(String query)
{
- return getSession().prepare(query);
+ PreparedStatement stmt = stmts.get(query);
+ if (stmt != null)
+ return stmt;
+ synchronized (stmts)
+ {
+ stmt = stmts.get(query);
+ if (stmt != null)
+ return stmt;
+ stmt = getSession().prepare(query);
+ stmts.put(query, stmt);
+ }
+ return stmt;
}
public void connect(ProtocolOptions.Compression compression) throws Exception
@@ -116,7 +131,7 @@ public class JavaDriverClient
* @param cl
* @return
*/
- ConsistencyLevel from(org.apache.cassandra.db.ConsistencyLevel cl)
+ public static ConsistencyLevel from(org.apache.cassandra.db.ConsistencyLevel cl)
{
switch (cl)
{