
com.yugabyte.sample.apps.CassandraTransactionalKeyValue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of yb-sample-apps Show documentation
Show all versions of yb-sample-apps Show documentation
Sample applications for benchmarking YugaByte DB functionality on various workload types.
The newest version!
// Copyright (c) YugaByte, Inc.
//
// Licensed 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 com.yugabyte.sample.apps;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import org.apache.log4j.Logger;
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.yugabyte.sample.common.SimpleLoadGenerator.Key;
/**
* This workload writes and reads some random string keys from a CQL server. By default, this app
* inserts a million keys, and reads/updates them indefinitely.
*/
public class CassandraTransactionalKeyValue extends CassandraKeyValue {
private static final Logger LOG = Logger.getLogger(CassandraTransactionalKeyValue.class);
// Static initialization of this workload's config. These are good defaults for getting a decent
// read dominated workload on a reasonably powered machine. Exact IOPS will of course vary
// depending on the machine and what resources it has to spare.
static {
// Disable the read-write percentage.
appConfig.readIOPSPercentage = -1;
// Set the read and write threads to 1 each.
appConfig.numReaderThreads = 24;
appConfig.numWriterThreads = 2;
// The number of keys to read.
appConfig.numKeysToRead = -1;
// The number of keys to write. This is the combined total number of inserts and updates.
appConfig.numKeysToWrite = -1;
// The number of unique keys to write. This determines the number of inserts (as opposed to
// updates).
appConfig.numUniqueKeysToWrite = NUM_UNIQUE_KEYS;
}
// The default table name to create and use for CRUD ops.
private static final String DEFAULT_TABLE_NAME =
CassandraTransactionalKeyValue.class.getSimpleName();
public CassandraTransactionalKeyValue() {
}
@Override
public List getCreateTableStatements() {
String createStmt = String.format(
"CREATE TABLE IF NOT EXISTS %s (k varchar, v bigint, primary key (k)) " +
"WITH transactions = { 'enabled' : true };", getTableName());
return Arrays.asList(createStmt);
}
public String getTableName() {
return appConfig.tableName != null ? appConfig.tableName : DEFAULT_TABLE_NAME;
}
private PreparedStatement getPreparedSelect() {
return getPreparedSelect(String.format("SELECT k, v, writetime(v) FROM %s WHERE k in :k;",
getTableName()),
appConfig.localReads);
}
private void verifyValue(Key key, long value1, long value2) {
long keyNumber = key.asNumber();
if (keyNumber != value1 + value2) {
LOG.fatal("Value mismatch for key: " + key.toString() +
" != " + value1 + " + " + value2);
}
}
@Override
public long doRead() {
Key key = getSimpleLoadGenerator().getKeyToRead();
if (key == null) {
// There are no keys to read yet.
return 0;
}
// Do the read from Cassandra.
// Bind the select statement.
BoundStatement select = getPreparedSelect().bind(Arrays.asList(key.asString() + "_1",
key.asString() + "_2"));
ResultSet rs = getCassandraClient().execute(select);
List rows = rs.all();
if (rows.size() != 2) {
LOG.fatal("Read key: " + key.asString() + " expected 2 row in result, got " + rows.size());
return 1;
}
verifyValue(key, rows.get(0).getLong(1), rows.get(1).getLong(1));
if (rows.get(0).getLong(2) != rows.get(1).getLong(2)) {
LOG.fatal("Writetime mismatch for key: " + key.toString() + ", " +
rows.get(0).getLong(2) + " vs " + rows.get(1).getLong(2));
}
LOG.debug("Read key: " + key.toString());
return 1;
}
protected PreparedStatement getPreparedInsert() {
return getPreparedInsert(String.format(
"BEGIN TRANSACTION" +
" INSERT INTO %s (k, v) VALUES (:k1, :v1);" +
" INSERT INTO %s (k, v) VALUES (:k2, :v2);" +
"END TRANSACTION;",
getTableName(),
getTableName()));
}
@Override
public long doWrite(int threadIdx) {
Key key = getSimpleLoadGenerator().getKeyToWrite();
try {
// Do the write to Cassandra.
BoundStatement insert = null;
long keyNum = key.asNumber();
/* Generate two numbers that add up to the key, and use them as values */
long value1 = ThreadLocalRandom.current().nextLong(keyNum + 1);
long value2 = keyNum - value1;
insert = getPreparedInsert()
.bind()
.setString("k1", key.asString() + "_1")
.setString("k2", key.asString() + "_2")
.setLong("v1", value1)
.setLong("v2", value2);
ResultSet resultSet = getCassandraClient().execute(insert);
LOG.debug("Wrote key: " + key.toString() + ", return code: " + resultSet.toString());
getSimpleLoadGenerator().recordWriteSuccess(key);
return 1;
} catch (Exception e) {
getSimpleLoadGenerator().recordWriteFailure(key);
throw e;
}
}
@Override
public List getWorkloadDescription() {
return Arrays.asList(
"Key-value app with multi-row transactions. Each write txn inserts a pair of unique string keys with the same value.",
" There are multiple readers and writers that update these keys and read them in pair ",
"indefinitely. The number of reads and writes to perform can be specified as a parameter.");
}
@Override
public List getWorkloadOptionalArguments() {
return Arrays.asList(
"--num_unique_keys " + appConfig.numUniqueKeysToWrite,
"--num_reads " + appConfig.numKeysToRead,
"--num_writes " + appConfig.numKeysToWrite,
"--value_size " + appConfig.valueSize,
"--num_threads_read " + appConfig.numReaderThreads,
"--num_threads_write " + appConfig.numWriterThreads);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy