diff --git a/core/src/main/java/com/yahoo/ycsb/generator/IncrementingPrintableStringGenerator.java b/core/src/main/java/com/yahoo/ycsb/generator/IncrementingPrintableStringGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..82406f020a1a64c37b2c2cc0891da046c52120a8
--- /dev/null
+++ b/core/src/main/java/com/yahoo/ycsb/generator/IncrementingPrintableStringGenerator.java
@@ -0,0 +1,389 @@
+/**
+ * Copyright (c) 2016 YCSB contributors. All rights reserved.
+ *
+ * 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. See accompanying
+ * LICENSE file.
+ */
+package com.yahoo.ycsb.generator;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * A generator that produces strings of {@link #length} using a set of code points
+ * from {@link #characterSet}. Each time {@link #nextValue()} is executed, the string
+ * is incremented by one character. Eventually the string may rollover to the beginning
+ * and the user may choose to have the generator throw a NoSuchElementException at that 
+ * point or continue incrementing. (By default the generator will continue incrementing).
+ * <p>
+ * For example, if we set a length of 2 characters and the character set includes
+ * [A, B] then the generator output will be:
+ * <ul>
+ * <li>AA</li>
+ * <li>AB</li>
+ * <li>BA</li>
+ * <li>BB</li>
+ * <li>AA <-- rolled over</li>
+ * </ul>
+ * <p>
+ * This class includes some default character sets to choose from including ASCII
+ * and plane 0 UTF. 
+ */
+public class IncrementingPrintableStringGenerator extends Generator<String> {
+
+  /** Default string length for the generator. */
+  public static final int DEFAULTSTRINGLENGTH = 8;
+  
+  /**
+   * Set of all character types that include every symbol other than non-printable
+   * control characters.
+   */
+  public static final Set<Integer> CHAR_TYPES_ALL_BUT_CONTROL;
+  static {
+    CHAR_TYPES_ALL_BUT_CONTROL = new HashSet<Integer>(24);
+    // numbers
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.DECIMAL_DIGIT_NUMBER);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.LETTER_NUMBER);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.OTHER_NUMBER);
+    
+    // letters
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.UPPERCASE_LETTER);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.LOWERCASE_LETTER);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.TITLECASE_LETTER);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.OTHER_LETTER);
+    
+    // marks
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.COMBINING_SPACING_MARK);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.NON_SPACING_MARK);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.ENCLOSING_MARK);
+    
+    // punctuation
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.CONNECTOR_PUNCTUATION);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.DASH_PUNCTUATION);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.START_PUNCTUATION);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.END_PUNCTUATION);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.INITIAL_QUOTE_PUNCTUATION);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.FINAL_QUOTE_PUNCTUATION);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.OTHER_PUNCTUATION);
+    
+    // symbols
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.MATH_SYMBOL);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.CURRENCY_SYMBOL);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.MODIFIER_SYMBOL);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.OTHER_SYMBOL);
+    
+    // separators
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.SPACE_SEPARATOR);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.LINE_SEPARATOR);
+    CHAR_TYPES_ALL_BUT_CONTROL.add((int)Character.PARAGRAPH_SEPARATOR);
+  }
+  
+  /**
+   * Set of character types including only decimals, upper and lower case letters.
+   */
+  public static final Set<Integer> CHAR_TYPES_BASIC_ALPHA;
+  static {
+    CHAR_TYPES_BASIC_ALPHA = new HashSet<Integer>(2);
+    CHAR_TYPES_BASIC_ALPHA.add((int)Character.UPPERCASE_LETTER);
+    CHAR_TYPES_BASIC_ALPHA.add((int)Character.LOWERCASE_LETTER);
+  }
+  
+  /**
+   * Set of character types including only  decimals, upper and lower case letters.
+   */
+  public static final Set<Integer> CHAR_TYPES_BASIC_ALPHANUMERICS;
+  static {
+    CHAR_TYPES_BASIC_ALPHANUMERICS = new HashSet<Integer>(3);
+    CHAR_TYPES_BASIC_ALPHANUMERICS.add((int)Character.DECIMAL_DIGIT_NUMBER);
+    CHAR_TYPES_BASIC_ALPHANUMERICS.add((int)Character.UPPERCASE_LETTER);
+    CHAR_TYPES_BASIC_ALPHANUMERICS.add((int)Character.LOWERCASE_LETTER);
+  }
+  
+  /**
+   * Set of character types including only decimals, letter numbers, 
+   * other numbers, upper, lower, title case as well as letter modifiers 
+   * and other letters.
+   */
+  public static final Set<Integer> CHAR_TYPE_EXTENDED_ALPHANUMERICS;
+  static {
+    CHAR_TYPE_EXTENDED_ALPHANUMERICS = new HashSet<Integer>(8);
+    CHAR_TYPE_EXTENDED_ALPHANUMERICS.add((int)Character.DECIMAL_DIGIT_NUMBER);
+    CHAR_TYPE_EXTENDED_ALPHANUMERICS.add((int)Character.LETTER_NUMBER);
+    CHAR_TYPE_EXTENDED_ALPHANUMERICS.add((int)Character.OTHER_NUMBER);
+    CHAR_TYPE_EXTENDED_ALPHANUMERICS.add((int)Character.UPPERCASE_LETTER);
+    CHAR_TYPE_EXTENDED_ALPHANUMERICS.add((int)Character.LOWERCASE_LETTER);
+    CHAR_TYPE_EXTENDED_ALPHANUMERICS.add((int)Character.TITLECASE_LETTER);
+    CHAR_TYPE_EXTENDED_ALPHANUMERICS.add((int)Character.MODIFIER_LETTER);
+    CHAR_TYPE_EXTENDED_ALPHANUMERICS.add((int)Character.OTHER_LETTER);
+  }
+  
+  /** The character set to iterate over. */
+  private final int[] characterSet;
+  
+  /** An array indices matching a position in the output string. */
+  private int[] indices; 
+  
+  /** The length of the output string in characters. */
+  private final int length;
+  
+  /** The last value returned by the generator. Should be null if {@link #nextValue()} 
+   * has not been called.*/
+  private String lastValue;
+  
+  /** Whether or not to throw an exception when the string rolls over. */
+  private boolean throwExceptionOnRollover;
+  
+  /** Whether or not the generator has rolled over. */
+  private boolean hasRolledOver;
+  
+  /**
+   * Generates strings of 8 characters using only the upper and lower case alphabetical
+   * characters from the ASCII set. 
+   */
+  public IncrementingPrintableStringGenerator() {
+    this(DEFAULTSTRINGLENGTH, printableBasicAlphaASCIISet());
+  }
+  
+  /**
+   * Generates strings of {@link #length} characters using only the upper and lower 
+   * case alphabetical characters from the ASCII set. 
+   * @param length The length of string to return from the generator.
+   * @throws IllegalArgumentException if the length is less than one.
+   */
+  public IncrementingPrintableStringGenerator(final int length) {
+    this(length, printableBasicAlphaASCIISet());
+  }
+  
+  /**
+   * Generates strings of {@link #length} characters using the code points in
+   * {@link #characterSet}.
+   * @param length The length of string to return from the generator.
+   * @param characterSet A set of code points to choose from. Code points in the 
+   * set can be in any order, not necessarily lexical.
+   * @throws IllegalArgumentException if the length is less than one or the character
+   * set has fewer than one code points.
+   */
+  public IncrementingPrintableStringGenerator(final int length, final int[] characterSet) {
+    if (length < 1) {
+      throw new IllegalArgumentException("Length must be greater than or equal to 1");
+    }
+    if (characterSet == null || characterSet.length < 1) {
+      throw new IllegalArgumentException("Character set must have at least one character");
+    }
+    this.length = length;
+    this.characterSet = characterSet;
+    indices = new int[length];
+  }
+  
+  @Override
+  public String nextValue() {
+    if (hasRolledOver && throwExceptionOnRollover) {
+      throw new NoSuchElementException("The generator has rolled over to the beginning");
+    }
+    
+    final StringBuilder buffer = new StringBuilder(length);
+    for (int i = 0; i < length; i++) {
+      buffer.append(Character.toChars(characterSet[indices[i]]));
+    }
+    
+    // increment the indices;
+    for (int i = length - 1; i >= 0; --i) {
+      if (indices[i] >= characterSet.length - 1) {
+        indices[i] = 0;
+        if (i == 0 || characterSet.length == 1 && lastValue != null) {
+          hasRolledOver = true;
+        }
+      } else {
+        ++indices[i];
+        break;
+      }
+    }
+    
+    lastValue = buffer.toString();
+    return lastValue;
+  }
+
+  @Override
+  public String lastValue() {
+    return lastValue;
+  }
+
+  /** @param exceptionOnRollover Whether or not to throw an exception on rollover. */
+  public void setThrowExceptionOnRollover(final boolean exceptionOnRollover) {
+    this.throwExceptionOnRollover = exceptionOnRollover;
+  }
+  
+  /** @return Whether or not to throw an exception on rollover. */
+  public boolean getThrowExceptionOnRollover() {
+    return throwExceptionOnRollover;
+  }
+  
+  /**
+   * Returns an array of printable code points with only the upper and lower
+   * case alphabetical characters from the basic ASCII set.
+   * @return An array of code points
+   */
+  public static int[] printableBasicAlphaASCIISet() {
+    final List<Integer> validCharacters = 
+        generatePrintableCharacterSet(0, 127, null, false, CHAR_TYPES_BASIC_ALPHA);
+    final int[] characterSet = new int[validCharacters.size()];
+    for (int i = 0; i < validCharacters.size(); i++) {
+      characterSet[i] = validCharacters.get(i);
+    }
+    return characterSet;
+  }
+  
+  /**
+   * Returns an array of printable code points with the upper and lower case 
+   * alphabetical characters as well as the numeric values from the basic 
+   * ASCII set.
+   * @return An array of code points
+   */
+  public static int[] printableBasicAlphaNumericASCIISet() {
+    final List<Integer> validCharacters = 
+        generatePrintableCharacterSet(0, 127, null, false, CHAR_TYPES_BASIC_ALPHANUMERICS);
+    final int[] characterSet = new int[validCharacters.size()];
+    for (int i = 0; i < validCharacters.size(); i++) {
+      characterSet[i] = validCharacters.get(i);
+    }
+    return characterSet;
+  }
+  
+  /**
+   * Returns an array of printable code points with the entire basic ASCII table,
+   * including spaces. Excludes new lines.
+   * @return An array of code points
+   */
+  public static int[] fullPrintableBasicASCIISet() {
+    final List<Integer> validCharacters = 
+        generatePrintableCharacterSet(32, 127, null, false, null);
+    final int[] characterSet = new int[validCharacters.size()];
+    for (int i = 0; i < validCharacters.size(); i++) {
+      characterSet[i] = validCharacters.get(i);
+    }
+    return characterSet;
+  }
+  
+  /**
+   * Returns an array of printable code points with the entire basic ASCII table,
+   * including spaces and new lines.
+   * @return An array of code points
+   */
+  public static int[] fullPrintableBasicASCIISetWithNewlines() {
+    final List<Integer> validCharacters =new ArrayList<Integer>();
+    validCharacters.add(10); // newline
+    validCharacters.addAll(generatePrintableCharacterSet(32, 127, null, false, null));
+    final int[] characterSet = new int[validCharacters.size()];
+    for (int i = 0; i < validCharacters.size(); i++) {
+      characterSet[i] = validCharacters.get(i);
+    }
+    return characterSet;
+  }
+  
+  /**
+   * Returns an array of printable code points the first plane of Unicode characters
+   * including only the alpha-numeric values.
+   * @return An array of code points
+   */
+  public static int[] printableAlphaNumericPlaneZeroSet() {
+    final List<Integer> validCharacters = 
+        generatePrintableCharacterSet(0, 65535, null, false, CHAR_TYPES_BASIC_ALPHANUMERICS);
+    final int[] characterSet = new int[validCharacters.size()];
+    for (int i = 0; i < validCharacters.size(); i++) {
+      characterSet[i] = validCharacters.get(i);
+    }
+    return characterSet;
+  }
+  
+  /**
+   * Returns an array of printable code points the first plane of Unicode characters
+   * including all printable characters.
+   * @return An array of code points
+   */
+  public static int[] fullPrintablePlaneZeroSet() {
+    final List<Integer> validCharacters = 
+        generatePrintableCharacterSet(0, 65535, null, false, CHAR_TYPES_ALL_BUT_CONTROL);
+    final int[] characterSet = new int[validCharacters.size()];
+    for (int i = 0; i < validCharacters.size(); i++) {
+      characterSet[i] = validCharacters.get(i);
+    }
+    return characterSet;
+  }
+  
+  /**
+   * Generates a list of code points based on a range and filters.
+   * These can be used for generating strings with various ASCII and/or
+   * Unicode printable character sets for use with DBs that may have 
+   * character limitations.
+   * <p>
+   * Note that control, surrogate, format, private use and unassigned 
+   * code points are skipped.
+   * @param startCodePoint The starting code point, inclusive.
+   * @param lastCodePoint The final code point, inclusive.
+   * @param characterTypesFilter An optional set of allowable character
+   * types. See {@link Character} for types.
+   * @param isFilterAllowableList Determines whether the {@code allowableTypes}
+   * set is inclusive or exclusive. When true, only those code points that
+   * appear in the list will be included in the resulting set. Otherwise
+   * matching code points are excluded.
+   * @param allowableTypes An optional list of code points for inclusion or
+   * exclusion.
+   * @return A list of code points matching the given range and filters. The
+   * list may be empty but is guaranteed not to be null.
+   */
+  public static List<Integer> generatePrintableCharacterSet(
+      final int startCodePoint,
+      final int lastCodePoint, 
+      final Set<Integer> characterTypesFilter,
+      final boolean isFilterAllowableList,
+      final Set<Integer> allowableTypes) {
+    
+    // since we don't know the final size of the allowable character list we
+    // start with a list then we'll flatten it to an array.
+    final List<Integer> validCharacters = new ArrayList<Integer>(lastCodePoint);
+    
+    for (int codePoint = startCodePoint; codePoint <= lastCodePoint; ++codePoint) {
+      if (allowableTypes != null && 
+          !allowableTypes.contains(Character.getType(codePoint))) {
+        continue;
+      } else {
+        // skip control points, formats, surrogates, etc
+        final int type = Character.getType(codePoint);
+        if (type == Character.CONTROL ||
+            type == Character.SURROGATE ||
+            type == Character.FORMAT ||
+            type == Character.PRIVATE_USE ||
+            type == Character.UNASSIGNED) {
+          continue;
+        }
+      }
+      
+      if (characterTypesFilter != null) {
+        // if the filter is enabled then we need to make sure the code point 
+        // is in the allowable list if it's a whitelist or that the code point
+        // is NOT in the list if it's a blacklist.
+        if ((isFilterAllowableList && !characterTypesFilter.contains(codePoint)) ||
+            (characterTypesFilter.contains(codePoint))) {
+          continue;
+        }
+      }
+      
+      validCharacters.add(codePoint);
+    }
+    return validCharacters;
+  }
+  
+}
diff --git a/core/src/test/java/com/yahoo/ycsb/generator/TestIncrementingPrintableStringGenerator.java b/core/src/test/java/com/yahoo/ycsb/generator/TestIncrementingPrintableStringGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..eea3d507861563f21ced4c7a12ff168316539159
--- /dev/null
+++ b/core/src/test/java/com/yahoo/ycsb/generator/TestIncrementingPrintableStringGenerator.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright (c) 2016 YCSB contributors. All rights reserved.
+ *
+ * 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. See accompanying
+ * LICENSE file.
+ */
+package com.yahoo.ycsb.generator;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.fail;
+
+import java.util.NoSuchElementException;
+
+import org.testng.annotations.Test;
+
+public class TestIncrementingPrintableStringGenerator {
+  private final static int[] ATOC = new int[] { 65, 66, 67 };
+  
+  @Test
+  public void rolloverOK() throws Exception {
+    final IncrementingPrintableStringGenerator gen = 
+        new IncrementingPrintableStringGenerator(2, ATOC);
+    
+    assertNull(gen.lastValue());
+    assertEquals(gen.nextValue(), "AA");
+    assertEquals(gen.lastValue(), "AA");
+    assertEquals(gen.nextValue(), "AB");
+    assertEquals(gen.lastValue(), "AB");
+    assertEquals(gen.nextValue(), "AC");
+    assertEquals(gen.lastValue(), "AC");
+    assertEquals(gen.nextValue(), "BA");
+    assertEquals(gen.lastValue(), "BA");
+    assertEquals(gen.nextValue(), "BB");
+    assertEquals(gen.lastValue(), "BB");
+    assertEquals(gen.nextValue(), "BC");
+    assertEquals(gen.lastValue(), "BC");
+    assertEquals(gen.nextValue(), "CA");
+    assertEquals(gen.lastValue(), "CA");
+    assertEquals(gen.nextValue(), "CB");
+    assertEquals(gen.lastValue(), "CB");
+    assertEquals(gen.nextValue(), "CC");
+    assertEquals(gen.lastValue(), "CC");
+    assertEquals(gen.nextValue(), "AA"); // <-- rollover
+    assertEquals(gen.lastValue(), "AA");
+  }
+  
+  @Test
+  public void rolloverOneCharacterOK() throws Exception {
+    // It would be silly to create a generator with one character.
+    final IncrementingPrintableStringGenerator gen = 
+        new IncrementingPrintableStringGenerator(2, new int[] { 65 });
+    for (int i = 0; i < 5; i++) {
+      assertEquals(gen.nextValue(), "AA");
+    }
+  }
+  
+  @Test
+  public void rolloverException() throws Exception {
+    final IncrementingPrintableStringGenerator gen = 
+        new IncrementingPrintableStringGenerator(2, ATOC);
+    gen.setThrowExceptionOnRollover(true);
+    
+    int i = 0;
+    try {
+      while(i < 11) {
+        ++i;
+        gen.nextValue();
+      }
+      fail("Expected NoSuchElementException");
+    } catch (NoSuchElementException e) {
+      assertEquals(i, 10);
+    }
+  }
+  
+  @Test
+  public void rolloverOneCharacterException() throws Exception {
+    // It would be silly to create a generator with one character.
+    final IncrementingPrintableStringGenerator gen = 
+        new IncrementingPrintableStringGenerator(2, new int[] { 65 });
+    gen.setThrowExceptionOnRollover(true);
+    
+    int i = 0;
+    try {
+      while(i < 3) {
+        ++i;
+        gen.nextValue();
+      }
+      fail("Expected NoSuchElementException");
+    } catch (NoSuchElementException e) {
+      assertEquals(i, 2);
+    }
+  }
+  
+  @Test
+  public void invalidLengths() throws Exception {
+    try {
+      new IncrementingPrintableStringGenerator(0, ATOC);
+      fail("Expected IllegalArgumentException");
+    } catch (IllegalArgumentException e) { }
+    
+    try {
+      new IncrementingPrintableStringGenerator(-42, ATOC);
+      fail("Expected IllegalArgumentException");
+    } catch (IllegalArgumentException e) { }
+  }
+  
+  @Test
+  public void invalidCharacterSets() throws Exception {
+    try {
+      new IncrementingPrintableStringGenerator(2, null);
+      fail("Expected IllegalArgumentException");
+    } catch (IllegalArgumentException e) { }
+    
+    try {
+      new IncrementingPrintableStringGenerator(2, new int[] {});
+      fail("Expected IllegalArgumentException");
+    } catch (IllegalArgumentException e) { }
+  }
+}