Skip to content
Snippets Groups Projects
Commit 36d18d42 authored by Stanley Feng's avatar Stanley Feng Committed by Connor McCoy
Browse files

[dynamodb] Add HASH_AND_RANGE primary key type

Extend the dynamoDB client to support the HASH_AND_RANGE primary key
type. The default primary key type remains exactly the same as before:
HASH type. And the default behavior and processing logic also remains
exactly the same as before.

What's added is the support to benchmark a primary key type called
HASH_AND_RANGE which is one of two supported primary key types of
DynamoDB. Knowing the performance characteristics of the HASH_AND_RANGE
key is important for some users because that's the only practical way
for them to get strongly consistent query across multiple items.

See documentation in conf/dynamodb.properties for more details.
parent b116ee5a
No related branches found
No related tags found
No related merge requests found
......@@ -24,8 +24,50 @@
# Primarykey of table 'usertable'
#dynamodb.primaryKey = <firstname>
# If you set dynamodb.primaryKeyType to HASH_AND_RANGE, you must specify the
# hash key name of your primary key here. (see documentation below for details)
#dynamodb.hashKeyName = <hashid>
## Optional parameters
# The property "primaryKeyType" below specifies the type of primary key
# you have setup for the test table. There are two choices:
# - HASH (default)
# - HASH_AND_RANGE
#
# When testing the DB in HASH mode (which is the default), your table's
# primary key must be of the "HASH" key type, and the name of the primary key
# is specified via the dynamodb.primaryKey property. In this mode, all
# keys from YCSB are hashed across multiple hash partitions and
# performance of individual operations are good. However, query across
# multiple items is eventually consistent in this mode and relies on the
# global secondary index.
#
#
# When testing the DB in HASH_AND_RANGE mode, your table's primary key must be
# of the "HASH_AND_RANGE" key type. You need to specify the name of the
# hash key via the "dynamodb.hashKeyName" property and you also need to
# specify the name of the range key via the "dynamodb.primaryKey" property.
# In this mode, keys supplied by YCSB will be used as the range part of
# the primary key and the hash part of the primary key will have a fixed value.
# Optionally you can designate the value used in the hash part of the primary
# key via the dynamodb.hashKeyValue.
#
# The purpose of the HASH_AND_RANGE mode is to benchmark the performance
# characteristics of a single logical hash partition. This is useful because
# so far the only practical way to do strongly consistent query is to do it
# in a single hash partition (Whole table scan can be consistent but it becomes
# less practical when the table is really large). Therefore, for users who
# really want to have strongly consistent query, it's important for them to
# know the performance capabilities of a single logical hash partition so
# they can plan their application accordingly.
#dynamodb.primaryKeyType = HASH
#Optionally you can specify a value for the hash part of the primary key
#when testing in HASH_AND_RANG mode.
#dynamodb.hashKeyValue = <some value of your choice>
# Endpoint to connect to.For best latency, it is recommended
# to choose the endpoint which is closer to the client.
# Default is us-east-1
......
......@@ -56,8 +56,30 @@ import java.util.Vector;
public class DynamoDBClient extends DB {
/**
* Defines the primary key type used in this particular DB instance.
*
* By default, the primary key type is "HASH". Optionally, the user can
* choose to use hash_and_range key type. See documentation in the
* DynamoDB.Properties file for more details.
*/
private enum PrimaryKeyType {
HASH,
HASH_AND_RANGE
}
private static final String DEFAULT_HASH_KEY_VALUE = "YCSB_0";
private AmazonDynamoDBClient dynamoDB;
private String primaryKeyName;
private PrimaryKeyType primaryKeyType = PrimaryKeyType.HASH;
// If the user choose to use HASH_AND_RANGE as primary key type, then
// the following two variables become relevant. See documentation in the
// DynamoDB.Properties file for more details.
private String hashKeyValue;
private String hashKeyName;
private boolean debug = false;
private boolean consistentRead = false;
private String endpoint = "http://dynamodb.us-east-1.amazonaws.com";
......@@ -69,6 +91,7 @@ public class DynamoDBClient extends DB {
* Initialize any state for this DB. Called once per DB instance; there is
* one DB instance per client thread.
*/
@Override
public void init() throws DBException {
// initialize DynamoDb driver & table.
String debug = getProperties().getProperty("dynamodb.debug",null);
......@@ -80,6 +103,7 @@ public class DynamoDBClient extends DB {
String endpoint = getProperties().getProperty("dynamodb.endpoint",null);
String credentialsFile = getProperties().getProperty("dynamodb.awsCredentialsFile",null);
String primaryKey = getProperties().getProperty("dynamodb.primaryKey",null);
String primaryKeyTypeString = getProperties().getProperty("dynamodb.primaryKeyType", null);
String consistentReads = getProperties().getProperty("dynamodb.consistentReads",null);
String connectMax = getProperties().getProperty("dynamodb.connectMax",null);
......@@ -100,6 +124,32 @@ public class DynamoDBClient extends DB {
logger.error(errMsg);
}
if (null != primaryKeyTypeString) {
try {
this.primaryKeyType = PrimaryKeyType.valueOf(
primaryKeyTypeString.trim().toUpperCase());
} catch (IllegalArgumentException e) {
throw new DBException("Invalid primary key mode specified: " +
primaryKeyTypeString + ". Expecting HASH or HASH_AND_RANGE.");
}
}
if (this.primaryKeyType == PrimaryKeyType.HASH_AND_RANGE) {
// When the primary key type is HASH_AND_RANGE, keys used by YCSB
// are range keys so we can benchmark performance of individual hash
// partitions. In this case, the user must specify the hash key's name
// and optionally can designate a value for the hash key.
String hashKeyName = getProperties().getProperty("dynamodb.hashKeyName", null);
if (null == hashKeyName || hashKeyName.isEmpty()) {
throw new DBException("Must specify a non-empty hash key name " +
"when the primary key type is HASH_AND_RANGE.");
}
this.hashKeyName = hashKeyName;
this.hashKeyValue = getProperties().getProperty(
"dynamodb.hashKeyValue", DEFAULT_HASH_KEY_VALUE);
}
try {
AWSCredentials credentials = new PropertiesCredentials(new File(credentialsFile));
ClientConfiguration cconfig = new ClientConfiguration();
......@@ -233,6 +283,12 @@ public class DynamoDBClient extends DB {
Map<String, AttributeValue> attributes = createAttributes(values);
// adding primary key
attributes.put(primaryKeyName, new AttributeValue(key));
if (primaryKeyType == PrimaryKeyType.HASH_AND_RANGE) {
// If the primary key type is HASH_AND_RANGE, then what has been put
// into the attributes map above is the range key part of the primary
// key, we still need to put in the hash key part here.
attributes.put(hashKeyName, new AttributeValue(hashKeyValue));
}
PutItemRequest putItemRequest = new PutItemRequest(table, attributes);
PutItemResult res = null;
......@@ -289,8 +345,18 @@ public class DynamoDBClient extends DB {
return rItems;
}
private static Key createPrimaryKey(String key) {
Key k = new Key().withHashKeyElement(new AttributeValue().withS(key));
private Key createPrimaryKey(String key) {
Key k;
if (primaryKeyType == PrimaryKeyType.HASH) {
k = new Key().withHashKeyElement(new AttributeValue().withS(key));
} else if (primaryKeyType == PrimaryKeyType.HASH_AND_RANGE) {
k = new Key()
.withHashKeyElement(new AttributeValue().withS(hashKeyValue))
.withRangeKeyElement(new AttributeValue().withS(key));
} else {
throw new RuntimeException("Assertion Error: impossible primary key"
+ " type");
}
return k;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment