diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..fa3de0bbd17e20606d550c1e8fc7cb35792e414d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,81 @@
+#
+# Running 'make -f Makefile.download-db-libs' will automatically download all 
+# of the libraries needed to build the YCSB drivers.
+#
+CASSANDRA_5_DIR=db/cassandra-0.5/lib
+CASSANDRA_5_FILE=apache-cassandra-0.5.1-bin.tar.gz
+CASSANDRA_6_DIR=db/cassandra-0.6/lib
+CASSANDRA_6_FILE=apache-cassandra-0.6.13-bin.tar.gz
+CASSANDRA_7_DIR=db/cassandra-0.7/lib
+CASSANDRA_7_FILE=apache-cassandra-0.7.9-bin.tar.gz
+CASSANDRA_8_DIR=db/cassandra-0.8/lib
+CASSANDRA_8_FILE=apache-cassandra-0.8.7-bin.tar.gz
+HBASE_DIR=db/hbase/lib
+HBASE_FILE=hbase-0.90.4.tar.gz
+INFINISPAN_DIR=db/infinispan-5.0/lib
+INFINISPAN_FILE=infinispan-5.0.0.CR8-bin.zip
+MONGODB_DIR=db/mongodb/lib
+MONGODB_FILE=mongo-2.7.2.jar
+REDIS_DIR=db/redis/lib
+REDIS_FILE=jedis-2.0.0.jar
+VOLDEMORT_DIR=db/voldemort/lib
+VOLDEMORT_FILE=voldemort-0.90.1.tar.gz
+
+.PHONY: build
+build: download-database-deps
+	ant -q -e compile
+	grep name=\"dbcompile build.xml | perl -ne '$$_=~/name=\"(.+)\"\s+depends/; print "$$1\n"; system "ant -q -e $$1"'
+
+download-database-deps:  $(CASSANDRA_5_DIR)/$(CASSANDRA_5_FILE) \
+			 $(CASSANDRA_6_DIR)/$(CASSANDRA_6_FILE) \
+			 $(CASSANDRA_7_DIR)/$(CASSANDRA_7_FILE) \
+			 $(CASSANDRA_8_DIR)/$(CASSANDRA_8_FILE) \
+			 $(HBASE_DIR)/$(HBASE_FILE)             \
+			 $(INFINISPAN_DIR)/$(INFINISPAN_FILE)   \
+			 $(MONGODB_DIR)/$(MONGODB_FILE)   \
+			 $(REDIS_DIR)/$(REDIS_FILE)   \
+			 $(VOLDEMORT_DIR)/$(VOLDEMORT_FILE)   \
+
+$(CASSANDRA_5_DIR)/$(CASSANDRA_5_FILE) :
+	wget http://archive.apache.org/dist/cassandra/0.5.1/$(CASSANDRA_5_FILE)\
+		 -O $(CASSANDRA_5_DIR)/$(CASSANDRA_5_FILE)
+	tar -C $(CASSANDRA_5_DIR) -zxf $(CASSANDRA_5_DIR)/$(CASSANDRA_5_FILE)
+
+$(CASSANDRA_6_DIR)/$(CASSANDRA_6_FILE) :
+	wget http://archive.apache.org/dist/cassandra/0.6.13/$(CASSANDRA_6_FILE)\
+		 -O $(CASSANDRA_6_DIR)/$(CASSANDRA_6_FILE)
+	tar -C $(CASSANDRA_6_DIR) -zxf $(CASSANDRA_6_DIR)/$(CASSANDRA_6_FILE)
+
+$(CASSANDRA_7_DIR)/$(CASSANDRA_7_FILE) :
+	wget http://archive.apache.org/dist/cassandra/0.7.9/$(CASSANDRA_7_FILE)\
+		 -O $(CASSANDRA_7_DIR)/$(CASSANDRA_7_FILE)
+	tar -C $(CASSANDRA_7_DIR) -zxf $(CASSANDRA_7_DIR)/$(CASSANDRA_7_FILE)
+
+$(CASSANDRA_8_DIR)/$(CASSANDRA_8_FILE) :
+	wget http://archive.apache.org/dist/cassandra/0.8.7/$(CASSANDRA_8_FILE)\
+		 -O $(CASSANDRA_8_DIR)/$(CASSANDRA_8_FILE)
+	tar -C $(CASSANDRA_8_DIR) -zxf $(CASSANDRA_8_DIR)/$(CASSANDRA_8_FILE)
+
+$(HBASE_DIR)/$(HBASE_FILE) :
+	wget http://archive.apache.org/dist/hbase/hbase-0.90.4/$(HBASE_FILE)\
+		 -O $(HBASE_DIR)/$(HBASE_FILE)
+	tar -C $(HBASE_DIR) -zxf $(HBASE_DIR)/$(HBASE_FILE)
+
+$(INFINISPAN_DIR)/$(INFINISPAN_FILE) :
+	wget http://iweb.dl.sourceforge.net/project/infinispan/infinispan/5.0.0.CR8/$(INFINISPAN_FILE)\
+		 -O $(INFINISPAN_DIR)/$(INFINISPAN_FILE)
+	unzip -a $(INFINISPAN_DIR)/$(INFINISPAN_FILE) -d $(INFINISPAN_DIR)
+
+$(MONGODB_DIR)/$(MONGODB_FILE) :
+	wget https://github.com/downloads/mongodb/mongo-java-driver/$(MONGODB_FILE)\
+		 -O $(MONGODB_DIR)/$(MONGODB_FILE)
+
+$(REDIS_DIR)/$(REDIS_FILE) :
+	wget https://github.com/downloads/xetorthio/jedis/$(REDIS_FILE)\
+		 -O $(REDIS_DIR)/$(REDIS_FILE)
+
+$(VOLDEMORT_DIR)/$(VOLDEMORT_FILE) :
+	wget https://github.com/downloads/voldemort/voldemort/$(VOLDEMORT_FILE)\
+		 -O $(VOLDEMORT_DIR)/$(VOLDEMORT_FILE)
+	tar -C $(VOLDEMORT_DIR) -zxf $(VOLDEMORT_DIR)/$(VOLDEMORT_FILE)
+
diff --git a/build.xml b/build.xml
index a71c34226181bc9a642f265968bf98613ba60f47..56115521fb403f0c14101d11d0d72f553d6d52f8 100644
--- a/build.xml
+++ b/build.xml
@@ -72,20 +72,20 @@
 	
  	<target name="compile">
         <mkdir dir="${classes.dir}"/>
-        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="build.classpath" deprecation="on">
+        <javac includeantruntime="false" srcdir="${src.dir}" destdir="${classes.dir}" classpathref="build.classpath" deprecation="on">
           <compilerarg value="-Xlint:unchecked"/>
         </javac>
         <antcall target="makejar"/>
     </target>
 
-	<target name="dbcompile">
+    <target name="dbcompile">
 	    <path id="dbclasspath">
 	        <fileset dir="${db.dir}/lib" includes="**/*.jar"/>
 	        <fileset file="build/ycsb.jar"/>
 	    </path>
 		
     	<mkdir dir="${classes.dir}"/>
-        <javac srcdir="${db.dir}/src" destdir="${classes.dir}" classpathref="dbclasspath" deprecation="on">
+        <javac includeantruntime="false" srcdir="${db.dir}/src" destdir="${classes.dir}" classpathref="dbclasspath" deprecation="on">
           <compilerarg value="-Xlint:unchecked"/>
         </javac>
         <antcall target="makejar"/>
@@ -105,7 +105,7 @@
       <javadoc destdir="${doc.dir}/javadoc" packagenames="com.yahoo.ycsb,com.yahoo.ycsb.workloads,com.yahoo.ycsb.db,com.yahoo.ycsb.generator,com.yahoo.ycsb.measurements"> 
          <fileset dir="." defaultexcludes="yes">
            <include name="src/**"/>
-           <include name="db/**/src/**"/>
+           <include name="db/*/src/**"/>
          </fileset>
       </javadoc>
    </target>
diff --git a/changes b/changes
index 93b11bfa07a7a1d39eb34725e5291af3e92b622d..b9afc136e5bfd074028bfaca13a4e6e5fbc6c69d 100644
--- a/changes
+++ b/changes
@@ -13,6 +13,15 @@
         * gh-27 MongoDbClient was not working with non localhost URLs (arunxarun)
         * gh-29 Add simple sharding capabilities for JDBC driver (kibab)
         * gh-40 Merge Redis database interface layer (lehmannro)
+        * gh-42 Response latencies are measured in microseconds (mikewied)
+        * gh-43 Variable length fields (sears)
+        * gh-44 Constant occupancy workload (sears)
+        * gh-45 Modify DB API for efficient large object support (sears)
+        * gh-46 Fixed typo in RedisClient (Zlender)
+        * gh-49 Build fix (sears)
+        * gh-50 Switch unordered key generation from FNV32 to FNV64 (sears)
+        * gh-51 Improved Random Number Generation Performance and add Exponential distribution support (sears)
+        * gh-52 Mongo db fix (sears)
 
 0.1.3
 	* Voldemort binding (rsumbaly)
diff --git a/db/cassandra-0.5/src/com/yahoo/ycsb/db/CassandraClient5.java b/db/cassandra-0.5/src/com/yahoo/ycsb/db/CassandraClient5.java
index bf8b58f8a6f923bf89072711a1569db6f89e512b..19f9f52812c147c0962faa82b7fda8dc3b3c1360 100644
--- a/db/cassandra-0.5/src/com/yahoo/ycsb/db/CassandraClient5.java
+++ b/db/cassandra-0.5/src/com/yahoo/ycsb/db/CassandraClient5.java
@@ -135,7 +135,7 @@ public class CassandraClient5 extends DB
 	 * @param result A HashMap of field/value pairs for the result
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int read(String table, String key, Set<String> fields, HashMap<String,String> result)
+	public int read(String table, String key, Set<String> fields, HashMap<String,ByteIterator> result)
 	{
 	   Exception errorexception=null;
 	   
@@ -170,7 +170,7 @@ public class CassandraClient5 extends DB
 			for (ColumnOrSuperColumn oneresult : results)
 			{
 				Column column=oneresult.column;
-				result.put(new String(column.name),new String(column.value));
+				result.put(new String(column.name),new ByteArrayByteIterator(column.value));
 				
 				if (_debug)
 				{
@@ -214,7 +214,7 @@ public class CassandraClient5 extends DB
 	 * @param result A Vector of HashMaps, where each HashMap is a set field/value pairs for one record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-      public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,String>> result)
+      public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,ByteIterator>> result)
       {
 	 Exception errorexception=null;	 
 
@@ -248,12 +248,12 @@ public class CassandraClient5 extends DB
 			
 			for (KeySlice oneresult : results)
 			{
-				HashMap<String,String> tuple = new HashMap<String, String>();
+				HashMap<String,ByteIterator> tuple = new HashMap<String, ByteIterator>();
 				
 				for (ColumnOrSuperColumn onecol : oneresult.columns)
 				{
 					Column column=onecol.column;
-					tuple.put(new String(column.name),new String(column.value));
+					tuple.put(new String(column.name),new ByteArrayByteIterator(column.value));
 					
 					if (_debug)
 					{
@@ -296,7 +296,7 @@ public class CassandraClient5 extends DB
 	 * @param values A HashMap of field/value pairs to update in the record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int update(String table, String key, HashMap<String,String> values)
+	public int update(String table, String key, HashMap<String,ByteIterator> values)
 	{
 		return insert(table,key,values);
 	}
@@ -310,7 +310,7 @@ public class CassandraClient5 extends DB
 	 * @param values A HashMap of field/value pairs to insert in the record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int insert(String table, String key, HashMap<String,String> values)
+	public int insert(String table, String key, HashMap<String,ByteIterator> values)
 	{
 	   Exception errorexception=null;
 	   
@@ -327,7 +327,7 @@ public class CassandraClient5 extends DB
 		{
 			for (String field : values.keySet())
 			{
-				String val=values.get(field);
+				String val=values.get(field).toString();
 				Column col=new Column(field.getBytes("UTF-8"),val.getBytes("UTF-8"),timestamp);
 
 				ColumnOrSuperColumn c=new ColumnOrSuperColumn();
@@ -428,14 +428,14 @@ public class CassandraClient5 extends DB
 			System.exit(0);
 		}
 
-		HashMap<String,String> vals=new HashMap<String,String>();
-		vals.put("age","57");
-		vals.put("middlename","bradley");
-		vals.put("favoritecolor","blue");
+		HashMap<String,ByteIterator> vals=new HashMap<String,ByteIterator>();
+		vals.put("age",new StringByteIterator("57"));
+		vals.put("middlename",new StringByteIterator("bradley"));
+		vals.put("favoritecolor",new StringByteIterator("blue"));
 		int res=cli.insert("usertable","BrianFrankCooper",vals);
 		System.out.println("Result of insert: "+res);
 
-		HashMap<String,String> result=new HashMap<String,String>();
+		HashMap<String,ByteIterator> result=new HashMap<String,ByteIterator>();
 		HashSet<String> fields=new HashSet<String>();
 		fields.add("middlename");
 		fields.add("age");
diff --git a/db/cassandra-0.6/src/com/yahoo/ycsb/db/CassandraClient6.java b/db/cassandra-0.6/src/com/yahoo/ycsb/db/CassandraClient6.java
index 8c1967ff1b65cc718947c81bd947e2cbd7c98cfa..6d4a57252ad274e93c8585600c5cd5ea9174119c 100644
--- a/db/cassandra-0.6/src/com/yahoo/ycsb/db/CassandraClient6.java
+++ b/db/cassandra-0.6/src/com/yahoo/ycsb/db/CassandraClient6.java
@@ -132,7 +132,7 @@ public class CassandraClient6 extends DB
 	 * @param result A HashMap of field/value pairs for the result
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int read(String table, String key, Set<String> fields, HashMap<String,String> result)
+	public int read(String table, String key, Set<String> fields, HashMap<String,ByteIterator> result)
 	{
 	   Exception errorexception=null;
 	   
@@ -177,7 +177,7 @@ public class CassandraClient6 extends DB
 		   for (ColumnOrSuperColumn oneresult : results)
 		   {
 		      Column column=oneresult.column;
-		      result.put(new String(column.name),new String(column.value));
+		      result.put(new String(column.name),new ByteArrayByteIterator(column.value));
 		      
 		      if (_debug)
 		      {
@@ -221,7 +221,7 @@ public class CassandraClient6 extends DB
 	 * @param result A Vector of HashMaps, where each HashMap is a set field/value pairs for one record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-      public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,String>> result)
+      public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,ByteIterator>> result)
       {
 	 Exception errorexception=null;	 
 
@@ -261,12 +261,12 @@ public class CassandraClient6 extends DB
 			
 			for (KeySlice oneresult : results)
 			{
-				HashMap<String,String> tuple = new HashMap<String, String>();
+				HashMap<String,ByteIterator> tuple = new HashMap<String,ByteIterator>();
 				
 				for (ColumnOrSuperColumn onecol : oneresult.columns)
 				{
 					Column column=onecol.column;
-					tuple.put(new String(column.name),new String(column.value));
+					tuple.put(new String(column.name),new ByteArrayByteIterator(column.value));
 					
 					if (_debug)
 					{
@@ -309,7 +309,7 @@ public class CassandraClient6 extends DB
 	 * @param values A HashMap of field/value pairs to update in the record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int update(String table, String key, HashMap<String,String> values)
+	public int update(String table, String key, HashMap<String,ByteIterator> values)
 	{
 		return insert(table,key,values);
 	}
@@ -323,7 +323,7 @@ public class CassandraClient6 extends DB
 	 * @param values A HashMap of field/value pairs to insert in the record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int insert(String table, String key, HashMap<String,String> values)
+	public int insert(String table, String key, HashMap<String,ByteIterator> values)
 	{
 	   Exception errorexception=null;
 	   
@@ -340,8 +340,8 @@ public class CassandraClient6 extends DB
 		{
 			for (String field : values.keySet())
 			{
-				String val=values.get(field);
-				Column col=new Column(field.getBytes("UTF-8"),val.getBytes("UTF-8"),timestamp);
+				ByteIterator val=values.get(field);
+				Column col=new Column(field.getBytes("UTF-8"),val.toArray(),timestamp);
 
 				ColumnOrSuperColumn c=new ColumnOrSuperColumn();
 				c.setColumn(col);
@@ -441,14 +441,14 @@ public class CassandraClient6 extends DB
 			System.exit(0);
 		}
 
-		HashMap<String,String> vals=new HashMap<String,String>();
-		vals.put("age","57");
-		vals.put("middlename","bradley");
-		vals.put("favoritecolor","blue");
+		HashMap<String,ByteIterator> vals=new HashMap<String,ByteIterator>();
+		vals.put("age",new StringByteIterator("57"));
+		vals.put("middlename",new StringByteIterator("bradley"));
+		vals.put("favoritecolor",new StringByteIterator("blue"));
 		int res=cli.insert("usertable","BrianFrankCooper",vals);
 		System.out.println("Result of insert: "+res);
 
-		HashMap<String,String> result=new HashMap<String,String>();
+		HashMap<String,ByteIterator> result=new HashMap<String,ByteIterator>();
 		HashSet<String> fields=new HashSet<String>();
 		fields.add("middlename");
 		fields.add("age");
diff --git a/db/cassandra-0.7/src/com/yahoo/ycsb/db/CassandraClient7.java b/db/cassandra-0.7/src/com/yahoo/ycsb/db/CassandraClient7.java
index c4fac12469979684de10cff72d11d3588f2aaaa5..c5a39692b9d37216ad46e24afbb02125b8cca533 100644
--- a/db/cassandra-0.7/src/com/yahoo/ycsb/db/CassandraClient7.java
+++ b/db/cassandra-0.7/src/com/yahoo/ycsb/db/CassandraClient7.java
@@ -179,7 +179,7 @@ public class CassandraClient7 extends DB
    *          A HashMap of field/value pairs for the result
    * @return Zero on success, a non-zero error code on error
    */
-  public int read(String table, String key, Set<String> fields, HashMap<String, String> result)
+  public int read(String table, String key, Set<String> fields, HashMap<String, ByteIterator> result)
   {
     if (!_table.equals(table)) {
       try 
@@ -224,13 +224,13 @@ public class CassandraClient7 extends DB
 
         Column column;
         String name;
-        String value;
+        ByteIterator value;
         for (ColumnOrSuperColumn oneresult : results)
         {
 
           column = oneresult.column;
 	        name = new String(column.name.array(), column.name.position()+column.name.arrayOffset(), column.name.remaining());
-      	  value = new String(column.value.array(), column.value.position()+column.value.arrayOffset(), column.value.remaining());
+      	  value = new ByteArrayByteIterator(column.value.array(), column.value.position()+column.value.arrayOffset(), column.value.remaining());
 
           result.put(name,value);
 
@@ -282,7 +282,7 @@ public class CassandraClient7 extends DB
    * @return Zero on success, a non-zero error code on error
    */
   public int scan(String table, String startkey, int recordcount, Set<String> fields,
-      Vector<HashMap<String, String>> result)
+      Vector<HashMap<String, ByteIterator>> result)
   {
     if (!_table.equals(table)) {
       try 
@@ -327,19 +327,19 @@ public class CassandraClient7 extends DB
           System.out.println("Scanning startkey: " + startkey);
         }
 
-        HashMap<String, String> tuple;
+        HashMap<String, ByteIterator> tuple;
         for (KeySlice oneresult : results)
         {
-          tuple = new HashMap<String, String>();
+          tuple = new HashMap<String, ByteIterator>();
           
           Column column;
           String name;
-          String value;
+          ByteIterator value;
           for (ColumnOrSuperColumn onecol : oneresult.columns)
           {
 	          column = onecol.column;
       	    name = new String(column.name.array(), column.name.position()+column.name.arrayOffset(), column.name.remaining());
-      	    value = new String(column.value.array(), column.value.position()+column.value.arrayOffset(), column.value.remaining());
+      	    value = new ByteArrayByteIterator(column.value.array(), column.value.position()+column.value.arrayOffset(), column.value.remaining());
             
       	    tuple.put(name, value);
 
@@ -386,7 +386,7 @@ public class CassandraClient7 extends DB
    *          A HashMap of field/value pairs to update in the record
    * @return Zero on success, a non-zero error code on error
    */
-  public int update(String table, String key, HashMap<String, String> values)
+  public int update(String table, String key, HashMap<String, ByteIterator> values)
   {
     return insert(table, key, values);
   }
@@ -404,7 +404,7 @@ public class CassandraClient7 extends DB
    *          A HashMap of field/value pairs to insert in the record
    * @return Zero on success, a non-zero error code on error
    */
-  public int insert(String table, String key, HashMap<String, String> values)
+  public int insert(String table, String key, HashMap<String, ByteIterator> values)
   {
     if (!_table.equals(table)) {
       try 
@@ -432,11 +432,11 @@ public class CassandraClient7 extends DB
         ByteBuffer wrappedKey = ByteBuffer.wrap(key.getBytes("UTF-8"));
 
         ColumnOrSuperColumn column;
-        for (Map.Entry<String, String> entry : values.entrySet())
+        for (Map.Entry<String, ByteIterator> entry : values.entrySet())
         {
           column = new ColumnOrSuperColumn();
           column.setColumn( new Column( ByteBuffer.wrap(entry.getKey().getBytes("UTF-8")), 
-                                        ByteBuffer.wrap(entry.getValue().getBytes("UTF-8")), 
+                                        ByteBuffer.wrap(entry.getValue().toArray()),
                                         System.currentTimeMillis()) );
                                         
           mutations.add(new Mutation().setColumn_or_supercolumn(column));
@@ -543,14 +543,14 @@ public class CassandraClient7 extends DB
       System.exit(0);
     }
 
-    HashMap<String, String> vals = new HashMap<String, String>();
-    vals.put("age", "57");
-    vals.put("middlename", "bradley");
-    vals.put("favoritecolor", "blue");
+    HashMap<String, ByteIterator> vals = new HashMap<String, ByteIterator>();
+    vals.put("age", new StringByteIterator("57"));
+    vals.put("middlename", new StringByteIterator("bradley"));
+    vals.put("favoritecolor", new StringByteIterator("blue"));
     int res = cli.insert("usertable", "BrianFrankCooper", vals);
     System.out.println("Result of insert: " + res);
 
-    HashMap<String, String> result = new HashMap<String, String>();
+    HashMap<String, ByteIterator> result = new HashMap<String, ByteIterator>();
     HashSet<String> fields = new HashSet<String>();
     fields.add("middlename");
     fields.add("age");
diff --git a/db/cassandra-0.8/src/com/yahoo/ycsb/db/CassandraClient8.java b/db/cassandra-0.8/src/com/yahoo/ycsb/db/CassandraClient8.java
index 9d760c59114a572ba965745203fc0cf17a9438cb..ec8abf3234eea3aec767789ba09b0275e0a6bdf5 100644
--- a/db/cassandra-0.8/src/com/yahoo/ycsb/db/CassandraClient8.java
+++ b/db/cassandra-0.8/src/com/yahoo/ycsb/db/CassandraClient8.java
@@ -179,7 +179,7 @@ public class CassandraClient8 extends DB
    *          A HashMap of field/value pairs for the result
    * @return Zero on success, a non-zero error code on error
    */
-  public int read(String table, String key, Set<String> fields, HashMap<String, String> result)
+  public int read(String table, String key, Set<String> fields, HashMap<String, ByteIterator> result)
   {
     if (!_table.equals(table)) {
       try 
@@ -224,13 +224,13 @@ public class CassandraClient8 extends DB
 
         Column column;
         String name;
-        String value;
+        ByteIterator value;
         for (ColumnOrSuperColumn oneresult : results)
         {
 
           column = oneresult.column;
 	        name = new String(column.name.array(), column.name.position()+column.name.arrayOffset(), column.name.remaining());
-      	  value = new String(column.value.array(), column.value.position()+column.value.arrayOffset(), column.value.remaining());
+      	  value = new ByteArrayByteIterator(column.value.array(), column.value.position()+column.value.arrayOffset(), column.value.remaining());
 
           result.put(name,value);
 
@@ -282,7 +282,7 @@ public class CassandraClient8 extends DB
    * @return Zero on success, a non-zero error code on error
    */
   public int scan(String table, String startkey, int recordcount, Set<String> fields,
-      Vector<HashMap<String, String>> result)
+      Vector<HashMap<String, ByteIterator>> result)
   {
     if (!_table.equals(table)) {
       try 
@@ -327,19 +327,19 @@ public class CassandraClient8 extends DB
           System.out.println("Scanning startkey: " + startkey);
         }
 
-        HashMap<String, String> tuple;
+        HashMap<String, ByteIterator> tuple;
         for (KeySlice oneresult : results)
         {
-          tuple = new HashMap<String, String>();
+          tuple = new HashMap<String, ByteIterator>();
           
           Column column;
           String name;
-          String value;
+          ByteIterator value;
           for (ColumnOrSuperColumn onecol : oneresult.columns)
           {
 	          column = onecol.column;
       	    name = new String(column.name.array(), column.name.position()+column.name.arrayOffset(), column.name.remaining());
-      	    value = new String(column.value.array(), column.value.position()+column.value.arrayOffset(), column.value.remaining());
+      	    value = new ByteArrayByteIterator(column.value.array(), column.value.position()+column.value.arrayOffset(), column.value.remaining());
             
       	    tuple.put(name, value);
 
@@ -386,7 +386,7 @@ public class CassandraClient8 extends DB
    *          A HashMap of field/value pairs to update in the record
    * @return Zero on success, a non-zero error code on error
    */
-  public int update(String table, String key, HashMap<String, String> values)
+  public int update(String table, String key, HashMap<String, ByteIterator> values)
   {
     return insert(table, key, values);
   }
@@ -404,7 +404,7 @@ public class CassandraClient8 extends DB
    *          A HashMap of field/value pairs to insert in the record
    * @return Zero on success, a non-zero error code on error
    */
-  public int insert(String table, String key, HashMap<String, String> values)
+  public int insert(String table, String key, HashMap<String, ByteIterator> values)
   {
     if (!_table.equals(table)) {
       try 
@@ -433,11 +433,11 @@ public class CassandraClient8 extends DB
 
         Column col;
         ColumnOrSuperColumn column;
-        for (Map.Entry<String, String> entry : values.entrySet())
+        for (Map.Entry<String, ByteIterator> entry : values.entrySet())
         {
           col = new Column();
           col.setName(ByteBuffer.wrap(entry.getKey().getBytes("UTF-8")));
-          col.setValue(ByteBuffer.wrap(entry.getValue().getBytes("UTF-8")));
+          col.setValue(ByteBuffer.wrap(entry.getValue().toArray()));
           col.setTimestamp(System.currentTimeMillis());
 
           column = new ColumnOrSuperColumn();
@@ -547,14 +547,14 @@ public class CassandraClient8 extends DB
       System.exit(0);
     }
 
-    HashMap<String, String> vals = new HashMap<String, String>();
-    vals.put("age", "57");
-    vals.put("middlename", "bradley");
-    vals.put("favoritecolor", "blue");
+    HashMap<String, ByteIterator> vals = new HashMap<String, ByteIterator>();
+    vals.put("age", new StringByteIterator("57"));
+    vals.put("middlename", new StringByteIterator("bradley"));
+    vals.put("favoritecolor", new StringByteIterator("blue"));
     int res = cli.insert("usertable", "BrianFrankCooper", vals);
     System.out.println("Result of insert: " + res);
 
-    HashMap<String, String> result = new HashMap<String, String>();
+    HashMap<String, ByteIterator> result = new HashMap<String, ByteIterator>();
     HashSet<String> fields = new HashSet<String>();
     fields.add("middlename");
     fields.add("age");
diff --git a/db/hbase/src/com/yahoo/ycsb/db/HBaseClient.java b/db/hbase/src/com/yahoo/ycsb/db/HBaseClient.java
index 0a5c3f52ec6f51abebecfe3867abfe7de5814fee..c2ecf75ce79e59e60b9db779ce7979e207a2accf 100644
--- a/db/hbase/src/com/yahoo/ycsb/db/HBaseClient.java
+++ b/db/hbase/src/com/yahoo/ycsb/db/HBaseClient.java
@@ -19,6 +19,9 @@ package com.yahoo.ycsb.db;
 
 
 import com.yahoo.ycsb.DBException;
+import com.yahoo.ycsb.ByteIterator;
+import com.yahoo.ycsb.ByteArrayByteIterator;
+import com.yahoo.ycsb.StringByteIterator;
 
 import java.io.IOException;
 import java.util.*;
@@ -123,7 +126,7 @@ public class HBaseClient extends com.yahoo.ycsb.DB
 	 * @param result A HashMap of field/value pairs for the result
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int read(String table, String key, Set<String> fields, HashMap<String,String> result)
+	public int read(String table, String key, Set<String> fields, HashMap<String,ByteIterator> result)
     {
         //if this is a "new" table, init HTable object.  Else, use existing one
         if (!_table.equals(table)) {
@@ -171,7 +174,7 @@ public class HBaseClient extends com.yahoo.ycsb.DB
   for (KeyValue kv : r.raw()) {
     result.put(
         Bytes.toString(kv.getQualifier()),
-        Bytes.toString(kv.getValue()));
+        new ByteArrayByteIterator(kv.getValue()));
     if (_debug) {
       System.out.println("Result for field: "+Bytes.toString(kv.getQualifier())+
           " is: "+Bytes.toString(kv.getValue()));
@@ -191,7 +194,7 @@ public class HBaseClient extends com.yahoo.ycsb.DB
 	 * @param result A Vector of HashMaps, where each HashMap is a set field/value pairs for one record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-    public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,String>> result)
+    public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,ByteIterator>> result)
     {
         //if this is a "new" table, init HTable object.  Else, use existing one
         if (!_table.equals(table)) {
@@ -240,12 +243,12 @@ public class HBaseClient extends com.yahoo.ycsb.DB
                     System.out.println("Got scan result for key: "+key);
                 }
 
-                HashMap<String,String> rowResult = new HashMap<String, String>();
+                HashMap<String,ByteIterator> rowResult = new HashMap<String, ByteIterator>();
 
                 for (KeyValue kv : rr.raw()) {
                   rowResult.put(
                       Bytes.toString(kv.getQualifier()),
-                      Bytes.toString(kv.getValue()));
+                      new ByteArrayByteIterator(kv.getValue()));
                 }
                 //add rowResult to result vector
                 result.add(rowResult);
@@ -282,7 +285,7 @@ public class HBaseClient extends com.yahoo.ycsb.DB
      * @param values A HashMap of field/value pairs to update in the record
      * @return Zero on success, a non-zero error code on error
      */
-    public int update(String table, String key, HashMap<String,String> values)
+    public int update(String table, String key, HashMap<String,ByteIterator> values)
     {
         //if this is a "new" table, init HTable object.  Else, use existing one
         if (!_table.equals(table)) {
@@ -304,13 +307,13 @@ public class HBaseClient extends com.yahoo.ycsb.DB
             System.out.println("Setting up put for key: "+key);
         }
         Put p = new Put(Bytes.toBytes(key));
-        for (Map.Entry<String, String> entry : values.entrySet())
+        for (Map.Entry<String, ByteIterator> entry : values.entrySet())
         {
             if (_debug) {
                 System.out.println("Adding field/value " + entry.getKey() + "/"+
                   entry.getValue() + " to put request");
             }	       
-            p.add(_columnFamilyBytes,Bytes.toBytes(entry.getKey()),Bytes.toBytes(entry.getValue()));
+            p.add(_columnFamilyBytes,Bytes.toBytes(entry.getKey()),entry.getValue().toArray());
         }
 
         try 
@@ -342,7 +345,7 @@ public class HBaseClient extends com.yahoo.ycsb.DB
      * @param values A HashMap of field/value pairs to insert in the record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int insert(String table, String key, HashMap<String,String> values)
+	public int insert(String table, String key, HashMap<String,ByteIterator> values)
     {
         return update(table,key,values);
     }
@@ -456,7 +459,7 @@ public class HBaseClient extends com.yahoo.ycsb.DB
                             HashSet<String> scanFields = new HashSet<String>();
                             scanFields.add("field1");
                             scanFields.add("field3");
-                            Vector<HashMap<String,String>> scanResults = new Vector<HashMap<String,String>>();
+                            Vector<HashMap<String,ByteIterator>> scanResults = new Vector<HashMap<String,ByteIterator>>();
                             rescode = cli.scan("table1","user2",20,null,scanResults);
                            
                             long en=System.currentTimeMillis();
diff --git a/db/infinispan-5.0/src/com/yahoo/ycsb/db/InfinispanClient.java b/db/infinispan-5.0/src/com/yahoo/ycsb/db/InfinispanClient.java
index b0e61dbfaf4ca85922fe1af188f3ff1c90d39b93..528ded5ca70d1a9dbf3ad311103883a96b9afa9d 100644
--- a/db/infinispan-5.0/src/com/yahoo/ycsb/db/InfinispanClient.java
+++ b/db/infinispan-5.0/src/com/yahoo/ycsb/db/InfinispanClient.java
@@ -2,6 +2,9 @@ package com.yahoo.ycsb.db;
 
 import com.yahoo.ycsb.DB;
 import com.yahoo.ycsb.DBException;
+import com.yahoo.ycsb.ByteIterator;
+import com.yahoo.ycsb.StringByteIterator;
+
 import org.infinispan.Cache;
 import org.infinispan.atomic.AtomicMap;
 import org.infinispan.atomic.AtomicMapLookup;
@@ -53,7 +56,7 @@ public class InfinispanClient extends DB {
       infinispanManager = null;
    }
 
-   public int read(String table, String key, Set<String> fields, HashMap<String, String> result) {
+   public int read(String table, String key, Set<String> fields, HashMap<String, ByteIterator> result) {
       try {
          Map<String, String> row;
          if (clustered) {
@@ -65,9 +68,9 @@ public class InfinispanClient extends DB {
          if (row != null) {
             result.clear();
             if (fields == null || fields.isEmpty()) {
-               result.putAll(row);
+		StringByteIterator.putAllAsByteIterators(result, row);
             } else {
-               for (String field : fields) result.put(field, row.get(field));
+	       for (String field : fields) result.put(field, new StringByteIterator(row.get(field)));
             }
          }
          return OK;
@@ -76,24 +79,24 @@ public class InfinispanClient extends DB {
       }
    }
 
-   public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String, String>> result) {
+   public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String, ByteIterator>> result) {
       logger.warn("Infinispan does not support scan semantics");
       return OK;
    }
 
-   public int update(String table, String key, HashMap<String, String> values) {
+   public int update(String table, String key, HashMap<String, ByteIterator> values) {
       try {
          if (clustered) {
             AtomicMap<String, String> row = AtomicMapLookup.getAtomicMap(infinispanManager.getCache(table), key);
-            row.putAll(values);
+            StringByteIterator.putAllAsStrings(row, values);
          } else {
             Cache<String, Map<String, String>> cache = infinispanManager.getCache(table);
             Map<String, String> row = cache.get(key);
             if (row == null) {
-               row = values;
+               row = StringByteIterator.getStringMap(values);
                cache.put(key, row);
             } else {
-               row.putAll(values);
+               StringByteIterator.putAllAsStrings(row, values);
             }
          }
 
@@ -103,12 +106,12 @@ public class InfinispanClient extends DB {
       }
    }
 
-   public int insert(String table, String key, HashMap<String, String> values) {
+   public int insert(String table, String key, HashMap<String, ByteIterator> values) {
       try {
          if (clustered) {
             AtomicMap<String, String> row = AtomicMapLookup.getAtomicMap(infinispanManager.getCache(table), key);
             row.clear();
-            row.putAll(values);
+            StringByteIterator.putAllAsStrings(row, values);
          } else {
             infinispanManager.getCache(table).put(key, values);
          }
diff --git a/db/jdbc/src/com/yahoo/ycsb/db/JdbcDBClient.java b/db/jdbc/src/com/yahoo/ycsb/db/JdbcDBClient.java
index 7bb3a1fcc06953502b0dd85ebbdd943ce8dde70f..8d1a6a7ea3411ce090cd1ded32dcd7d9268eeafa 100644
--- a/db/jdbc/src/com/yahoo/ycsb/db/JdbcDBClient.java
+++ b/db/jdbc/src/com/yahoo/ycsb/db/JdbcDBClient.java
@@ -19,6 +19,8 @@ package com.yahoo.ycsb.db;
 
 import com.yahoo.ycsb.DB;
 import com.yahoo.ycsb.DBException;
+import com.yahoo.ycsb.ByteIterator;
+import com.yahoo.ycsb.StringByteIterator;
 
 import java.sql.*;
 import java.util.*;
@@ -294,7 +296,7 @@ public class JdbcDBClient extends DB implements JdbcDBClientConstants {
 
 	@Override
 	public int read(String tableName, String key, Set<String> fields,
-			HashMap<String, String> result) {
+			HashMap<String, ByteIterator> result) {
 	  if (tableName == null) {
       return -1;
     }
@@ -316,7 +318,7 @@ public class JdbcDBClient extends DB implements JdbcDBClientConstants {
       if (result != null && fields != null) {
         for (String field : fields) {
           String value = resultSet.getString(field);
-          result.put(field, value);
+          result.put(field, new StringByteIterator(value));
         }
       }
       resultSet.close();
@@ -329,7 +331,7 @@ public class JdbcDBClient extends DB implements JdbcDBClientConstants {
 
 	@Override
 	public int scan(String tableName, String startKey, int recordcount,
-			Set<String> fields, Vector<HashMap<String, String>> result) {
+			Set<String> fields, Vector<HashMap<String, ByteIterator>> result) {
 	  if (tableName == null) {
       return -1;
     }
@@ -346,10 +348,10 @@ public class JdbcDBClient extends DB implements JdbcDBClientConstants {
       ResultSet resultSet = scanStatement.executeQuery();
       for (int i = 0; i < recordcount && resultSet.next(); i++) {
         if (result != null && fields != null) {
-          HashMap<String, String> values = new HashMap<String, String>();
+          HashMap<String, ByteIterator> values = new HashMap<String, ByteIterator>();
           for (String field : fields) {
             String value = resultSet.getString(field);
-            values.put(field, value);
+            values.put(field, new StringByteIterator(value));
           }
           result.add(values);
         }
@@ -363,7 +365,7 @@ public class JdbcDBClient extends DB implements JdbcDBClientConstants {
 	}
 
 	@Override
-	public int update(String tableName, String key, HashMap<String, String> values) {
+	public int update(String tableName, String key, HashMap<String, ByteIterator> values) {
 	  if (tableName == null) {
       return -1;
     }
@@ -378,8 +380,8 @@ public class JdbcDBClient extends DB implements JdbcDBClientConstants {
         updateStatement = createAndCacheUpdateStatement(type, key);
       }
       int index = 1;
-      for (Map.Entry<String, String> entry : values.entrySet()) {
-        updateStatement.setString(index++, entry.getValue());
+      for (Map.Entry<String, ByteIterator> entry : values.entrySet()) {
+        updateStatement.setString(index++, entry.getValue().toString());
       }
       updateStatement.setString(index, key);
       int result = updateStatement.executeUpdate();
@@ -392,7 +394,7 @@ public class JdbcDBClient extends DB implements JdbcDBClientConstants {
 	}
 
 	@Override
-	public int insert(String tableName, String key, HashMap<String, String> values) {
+	public int insert(String tableName, String key, HashMap<String, ByteIterator> values) {
 	  if (tableName == null) {
 	    return -1;
 	  }
@@ -408,8 +410,8 @@ public class JdbcDBClient extends DB implements JdbcDBClientConstants {
 	    }
       insertStatement.setString(1, key);
       int index = 2;
-      for (Map.Entry<String, String> entry : values.entrySet()) {
-        String field = entry.getValue();
+      for (Map.Entry<String, ByteIterator> entry : values.entrySet()) {
+        String field = entry.getValue().toString();
         insertStatement.setString(index++, field);
       }
       int result = insertStatement.executeUpdate();
diff --git a/db/mongodb/src/com/yahoo/ycsb/db/MongoDbClient.java b/db/mongodb/src/com/yahoo/ycsb/db/MongoDbClient.java
index ac9341892cefe1bae29c1b7914fd0b63cf48bdab..df70e148f7ba34b106ce009c6e3fcfa79ca975cf 100644
--- a/db/mongodb/src/com/yahoo/ycsb/db/MongoDbClient.java
+++ b/db/mongodb/src/com/yahoo/ycsb/db/MongoDbClient.java
@@ -14,6 +14,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Properties;
 import java.util.Set;
+import java.util.Map;
 import java.util.Vector;
 
 import org.bson.types.ObjectId;
@@ -29,6 +30,8 @@ import com.mongodb.WriteConcern;
 
 import com.yahoo.ycsb.DB;
 import com.yahoo.ycsb.DBException;
+import com.yahoo.ycsb.ByteIterator;
+import com.yahoo.ycsb.StringByteIterator;
 
 /**
  * MongoDB client for YCSB framework.
@@ -136,7 +139,7 @@ public class MongoDbClient extends DB {
      * @param values A HashMap of field/value pairs to insert in the record
      * @return Zero on success, a non-zero error code on error. See this class's description for a discussion of error codes.
      */
-    public int insert(String table, String key, HashMap<String, String> values) {
+    public int insert(String table, String key, HashMap<String, ByteIterator> values) {
         com.mongodb.DB db = null;
         try {
             db = mongo.getDB(database);
@@ -145,8 +148,9 @@ public class MongoDbClient extends DB {
 
             DBCollection collection = db.getCollection(table);
             DBObject r = new BasicDBObject().append("_id", key);
-            r.putAll(values);
-
+	    for(String k: values.keySet()) {
+		r.put(k, values.get(k).toString());
+	    }
             collection.setWriteConcern(writeConcern);
 
             collection.insert(r);
@@ -179,7 +183,7 @@ public class MongoDbClient extends DB {
      * @return Zero on success, a non-zero error code on error or "not found".
      */
     public int read(String table, String key, Set<String> fields,
-            HashMap<String, String> result) {
+            HashMap<String, ByteIterator> result) {
         com.mongodb.DB db = null;
         try {
             db = mongo.getDB(database);
@@ -228,7 +232,7 @@ public class MongoDbClient extends DB {
      * @param values A HashMap of field/value pairs to update in the record
      * @return Zero on success, a non-zero error code on error. See this class's description for a discussion of error codes.
      */
-    public int update(String table, String key, HashMap<String, String> values) {
+    public int update(String table, String key, HashMap<String, ByteIterator> values) {
         com.mongodb.DB db = null;
         try {
             db = mongo.getDB(database);
@@ -243,7 +247,7 @@ public class MongoDbClient extends DB {
             String tmpKey = null, tmpVal = null;
             while (keys.hasNext()) {
                 tmpKey = keys.next();
-                tmpVal = values.get(tmpKey);
+                tmpVal = values.get(tmpKey).toString();
                 fieldsToSet.put(tmpKey, tmpVal);
 
             }
@@ -281,7 +285,7 @@ public class MongoDbClient extends DB {
      * @return Zero on success, a non-zero error code on error. See this class's description for a discussion of error codes.
      */
     public int scan(String table, String startkey, int recordcount,
-            Set<String> fields, Vector<HashMap<String, String>> result) {
+            Set<String> fields, Vector<HashMap<String, ByteIterator>> result) {
         com.mongodb.DB db=null;
         try {
             db = mongo.getDB(database);
@@ -293,7 +297,7 @@ public class MongoDbClient extends DB {
             DBCursor cursor = collection.find(q).limit(recordcount);
             while (cursor.hasNext()) {
                 //toMap() returns a Map, but result.add() expects a Map<String,String>. Hence, the suppress warnings.
-                result.add((HashMap<String, String>) cursor.next().toMap());
+                result.add(StringByteIterator.getByteIteratorMap((Map<String,String>)cursor.next().toMap()));
             }
 
             return 0;
diff --git a/db/redis/src/com/yahoo/ycsb/db/RedisClient.java b/db/redis/src/com/yahoo/ycsb/db/RedisClient.java
index 650e6ca61e9eec8d37f783dfdecabb479c8b298a..0d5c3ff1efee1522b57d56688b90bf0be2e5fcba 100644
--- a/db/redis/src/com/yahoo/ycsb/db/RedisClient.java
+++ b/db/redis/src/com/yahoo/ycsb/db/RedisClient.java
@@ -8,7 +8,10 @@
 package com.yahoo.ycsb.db;
 import com.yahoo.ycsb.DB;
 import com.yahoo.ycsb.DBException;
+import com.yahoo.ycsb.ByteIterator;
+import com.yahoo.ycsb.StringByteIterator;
 
+import java.util.Map;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -68,9 +71,9 @@ public class RedisClient extends DB {
 
     @Override
     public int read(String table, String key, Set<String> fields,
-            HashMap<String, String> result) {
+            HashMap<String, ByteIterator> result) {
         if (fields == null) {
-            result.putAll(jedis.hgetAll(key));
+            StringByteIterator.putAllAsByteIterators(result, jedis.hgetAll(key));
         }
         else {
             String[] fieldArray = (String[])fields.toArray(new String[fields.size()]);
@@ -80,7 +83,8 @@ public class RedisClient extends DB {
             Iterator<String> valueIterator = values.iterator();
 
             while (fieldIterator.hasNext() && valueIterator.hasNext()) {
-                result.put(fieldIterator.next(), valueIterator.next());
+                result.put(fieldIterator.next(),
+			   new StringByteIterator(valueIterator.next()));
             }
             assert !fieldIterator.hasNext() && !valueIterator.hasNext();
         }
@@ -88,8 +92,8 @@ public class RedisClient extends DB {
     }
 
     @Override
-    public int insert(String table, String key, HashMap<String, String> values) {
-        if (jedis.hmset(key, values).equals("OK")) {
+    public int insert(String table, String key, HashMap<String, ByteIterator> values) {
+        if (jedis.hmset(key, StringByteIterator.getStringMap(values)).equals("OK")) {
             jedis.zadd(INDEX_KEY, hash(key), key);
             return 0;
         }
@@ -104,19 +108,19 @@ public class RedisClient extends DB {
     }
 
     @Override
-    public int update(String table, String key, HashMap<String, String> values) {
-        return jedis.hmset(key, values).equals("OK") ? 0 : 1;
+    public int update(String table, String key, HashMap<String, ByteIterator> values) {
+        return jedis.hmset(key, StringByteIterator.getStringMap(values)).equals("OK") ? 0 : 1;
     }
 
     @Override
     public int scan(String table, String startkey, int recordcount,
-            Set<String> fields, Vector<HashMap<String, String>> result) {
+            Set<String> fields, Vector<HashMap<String, ByteIterator>> result) {
         Set<String> keys = jedis.zrangeByScore(INDEX_KEY, hash(startkey),
                                 Double.POSITIVE_INFINITY, 0, recordcount);
 
-        HashMap<String, String> values;
+        HashMap<String, ByteIterator> values;
         for (String key : keys) {
-            values = new HashMap<String, String>();
+            values = new HashMap<String, ByteIterator>();
             read(table, key, fields, values);
             result.add(values);
         }
diff --git a/db/voldemort/src/com/yahoo/ycsb/db/VoldemortClient.java b/db/voldemort/src/com/yahoo/ycsb/db/VoldemortClient.java
index 1454d6e819c0b6c9b3d8812daf1d7d1a2bf17abd..84093b917ddb5357f6f105667c24c6b1d1398edf 100644
--- a/db/voldemort/src/com/yahoo/ycsb/db/VoldemortClient.java
+++ b/db/voldemort/src/com/yahoo/ycsb/db/VoldemortClient.java
@@ -15,6 +15,9 @@ import voldemort.versioning.Versioned;
 
 import com.yahoo.ycsb.DB;
 import com.yahoo.ycsb.DBException;
+import com.yahoo.ycsb.ByteIterator;
+import com.yahoo.ycsb.StringByteIterator;
+
 
 public class VoldemortClient extends DB {
 
@@ -66,17 +69,17 @@ public class VoldemortClient extends DB {
 	}
 
 	@Override
-	public int insert(String table, String key, HashMap<String, String> values) {
+	public int insert(String table, String key, HashMap<String, ByteIterator> values) {
 		if ( checkStore(table) == ERROR ) {
 			return ERROR;
 		}
-		storeClient.put(key, values);
+		storeClient.put(key, (HashMap<String,String>)StringByteIterator.getStringMap(values));
 		return OK;
 	}
 
 	@Override
 	public int read(String table, String key, Set<String> fields,
-			HashMap<String, String> result) {
+			HashMap<String, ByteIterator> result) {
 		if ( checkStore(table) == ERROR ) {
 			return ERROR;
 		}
@@ -90,23 +93,23 @@ public class VoldemortClient extends DB {
 			for (String field : fields) {
 				String val = versionedValue.getValue().get(field);
 				if ( val != null )
-					result.put(field, val);
+				    result.put(field, new StringByteIterator(val));
 			}
 		} else {
-			result.putAll(versionedValue.getValue());
+			StringByteIterator.putAllAsByteIterators(result, versionedValue.getValue());
 		}
 		return OK;
 	}
 
 	@Override
 	public int scan(String table, String startkey, int recordcount,
-			Set<String> fields, Vector<HashMap<String, String>> result) {
+			Set<String> fields, Vector<HashMap<String, ByteIterator>> result) {
 		logger.warn("Voldemort does not support Scan semantics");
 		return OK;
 	}
 
 	@Override
-	public int update(String table, String key, HashMap<String, String> values) {
+	public int update(String table, String key, HashMap<String, ByteIterator> values) {
 		if ( checkStore(table) == ERROR ) {
 			return ERROR;
 		}
@@ -117,12 +120,12 @@ public class VoldemortClient extends DB {
 		if ( versionedValue != null ) {
 			version = ((VectorClock) versionedValue.getVersion()).incremented(0, 1);
 			value = versionedValue.getValue();
-			for (Entry<String, String> entry : values.entrySet()) {
-				value.put(entry.getKey(), entry.getValue());
+			for (Entry<String, ByteIterator> entry : values.entrySet()) {
+				value.put(entry.getKey(), entry.getValue().toString());
 			}
 		} else {
 			version = new VectorClock();
-			value.putAll(values);
+			StringByteIterator.putAllAsStrings(value, values);
 		}
 		
 		storeClient.put(key, Versioned.value(value, version));
diff --git a/src/com/yahoo/ycsb/BasicDB.java b/src/com/yahoo/ycsb/BasicDB.java
index 19d626732ee04cc9bf8de651066d1c8af85064ad..9490451eff7e3be3d22ad30cbb1392d0712d8d6d 100644
--- a/src/com/yahoo/ycsb/BasicDB.java
+++ b/src/com/yahoo/ycsb/BasicDB.java
@@ -21,7 +21,6 @@ import java.util.HashMap;
 import java.util.Properties;
 import java.util.Set;
 import java.util.Enumeration;
-import java.util.Random;
 import java.util.Vector;
 
 
@@ -37,13 +36,11 @@ public class BasicDB extends DB
 	public static final String SIMULATE_DELAY_DEFAULT="0";
 	
 	
-	Random random;
 	boolean verbose;
 	int todelay;
 
 	public BasicDB()
 	{
-		random=new Random();
 		todelay=0;
 	}
 
@@ -54,7 +51,7 @@ public class BasicDB extends DB
 		{
 			try
 			{
-				Thread.sleep((long)random.nextInt(todelay));
+				Thread.sleep((long)Utils.random().nextInt(todelay));
 			}
 			catch (InterruptedException e)
 			{
@@ -98,7 +95,7 @@ public class BasicDB extends DB
 	 * @param result A HashMap of field/value pairs for the result
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int read(String table, String key, Set<String> fields, HashMap<String,String> result)
+	public int read(String table, String key, Set<String> fields, HashMap<String,ByteIterator> result)
 	{
 		delay();
 
@@ -133,7 +130,7 @@ public class BasicDB extends DB
 	 * @param result A Vector of HashMaps, where each HashMap is a set field/value pairs for one record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,String>> result)
+	public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,ByteIterator>> result)
 	{
 		delay();
 
@@ -167,7 +164,7 @@ public class BasicDB extends DB
 	 * @param values A HashMap of field/value pairs to update in the record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int update(String table, String key, HashMap<String,String> values)
+	public int update(String table, String key, HashMap<String,ByteIterator> values)
 	{
 		delay();
 
@@ -196,7 +193,7 @@ public class BasicDB extends DB
 	 * @param values A HashMap of field/value pairs to insert in the record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int insert(String table, String key, HashMap<String,String> values)
+	public int insert(String table, String key, HashMap<String,ByteIterator> values)
 	{
 		delay();
 
diff --git a/src/com/yahoo/ycsb/ByteArrayByteIterator.java b/src/com/yahoo/ycsb/ByteArrayByteIterator.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e36f98823c07cebaadf0ffc6394a5c6c0ebfd51
--- /dev/null
+++ b/src/com/yahoo/ycsb/ByteArrayByteIterator.java
@@ -0,0 +1,52 @@
+/**                                                                                                                                                                                
+ * Copyright (c) 2010 Yahoo! Inc. 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;
+
+public class ByteArrayByteIterator extends ByteIterator {
+	byte[] str;
+	int off;
+	final int len;
+	public ByteArrayByteIterator(byte[] s) {
+		this.str = s;
+		this.off = 0;
+		this.len = s.length;
+	}
+
+	public ByteArrayByteIterator(byte[] s, int off, int len) {
+		this.str = s;
+		this.off = off;
+		this.len = off + len;
+	}
+
+	@Override
+	public boolean hasNext() {
+		return off < len;
+	}
+
+	@Override
+	public byte nextByte() {
+		byte ret = str[off];
+		off++;
+		return ret;
+	}
+
+	@Override
+	public long bytesLeft() {
+		return len - off;
+	}
+
+}
diff --git a/src/com/yahoo/ycsb/ByteIterator.java b/src/com/yahoo/ycsb/ByteIterator.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bb3b63e36fcb6a95dbad08da0ea02cbf43f4005
--- /dev/null
+++ b/src/com/yahoo/ycsb/ByteIterator.java
@@ -0,0 +1,92 @@
+/**                                                                                                                                                                                
+ * Copyright (c) 2010 Yahoo! Inc. 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;
+
+import java.util.Iterator;
+import java.util.ArrayList;
+/**
+ * YCSB-specific buffer class.  ByteIterators are designed to support
+ * efficient field generation, and to allow backend drivers that can stream
+ * fields (instead of materializing them in RAM) to do so.
+ * <p>
+ * YCSB originially used String objects to represent field values.  This led to
+ * two performance issues.
+ * </p><p>
+ * First, it leads to unnecessary conversions between UTF-16 and UTF-8, both
+ * during field generation, and when passing data to byte-based backend
+ * drivers.
+ * </p><p>
+ * Second, Java strings are represented internally using UTF-16, and are
+ * built by appending to a growable array type (StringBuilder or
+ * StringBuffer), then calling a toString() method.  This leads to a 4x memory
+ * overhead as field values are being built, which prevented YCSB from
+ * driving large object stores.
+ * </p>
+ * The StringByteIterator class contains a number of convenience methods for
+ * backend drivers that convert between Map&lt;String,String&gt; and
+ * Map&lt;String,ByteBuffer&gt;.
+ *
+ * @author sears
+ */
+public abstract class ByteIterator implements Iterator<Byte> {
+
+	@Override
+	public abstract boolean hasNext();
+
+	@Override
+	public Byte next() {
+		throw new UnsupportedOperationException();
+		//return nextByte();
+	}
+
+	public abstract byte nextByte();
+        /** @return byte offset immediately after the last valid byte */
+	public int nextBuf(byte[] buf, int buf_off) {
+		int sz = buf_off;
+		while(sz < buf.length && hasNext()) {
+			buf[sz] = nextByte();
+			sz++;
+		}
+		return sz;
+	}
+
+	public abstract long bytesLeft();
+	
+	@Override
+	public void remove() {
+		throw new UnsupportedOperationException();
+	}
+
+	/** Consumes remaining contents of this object, and returns them as a string. */
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		while(this.hasNext()) { sb.append((char)nextByte()); }
+		return sb.toString();
+	}
+	/** Consumes remaining contents of this object, and returns them as a byte array. */
+	public byte[] toArray() {
+	    long left = bytesLeft();
+	    if(left != (int)left) { throw new ArrayIndexOutOfBoundsException("Too much data to fit in one array!"); }
+	    byte[] ret = new byte[(int)left];
+	    int off = 0;
+	    while(off < ret.length) {
+		off = nextBuf(ret, off);
+	    }
+	    return ret;
+	}
+
+}
diff --git a/src/com/yahoo/ycsb/Client.java b/src/com/yahoo/ycsb/Client.java
index 9da86041a6c2c601737b9681fb5e53bca2ed0894..64585f81a02276d04f0ba9142a9d7bf7375889f3 100644
--- a/src/com/yahoo/ycsb/Client.java
+++ b/src/com/yahoo/ycsb/Client.java
@@ -137,8 +137,6 @@ class StatusThread extends Thread
  */
 class ClientThread extends Thread
 {
-	static Random random=new Random();
-
 	DB _db;
 	boolean _dotransactions;
 	Workload _workload;
@@ -215,7 +213,7 @@ class ClientThread extends Thread
 		   //and the sleep() doesn't make sense for granularities < 1 ms anyway
 		   if ( (_target>0) && (_target<=1.0) ) 
 		   {
-		      sleep(random.nextInt((int)(1.0/_target)));
+		      sleep(Utils.random().nextInt((int)(1.0/_target)));
 		   }
 		}
 		catch (InterruptedException e)
diff --git a/src/com/yahoo/ycsb/CommandLine.java b/src/com/yahoo/ycsb/CommandLine.java
index c6fb13ded0dd9588a43dee8bd33fd02fc9309d3f..c177426beb5436f1dc120dfece7e531968ed3e40 100644
--- a/src/com/yahoo/ycsb/CommandLine.java
+++ b/src/com/yahoo/ycsb/CommandLine.java
@@ -293,10 +293,10 @@ public class CommandLine
 		     }
 		  }
 		  
-		  HashMap<String,String> result=new HashMap<String,String>();
+		  HashMap<String,ByteIterator> result=new HashMap<String,ByteIterator>();
 		  int ret=db.read(table,tokens[1],fields,result);
 		  System.out.println("Return code: "+ret);
-		  for (Map.Entry<String,String> ent : result.entrySet())
+		  for (Map.Entry<String,ByteIterator> ent : result.entrySet())
 		  {
 		     System.out.println(ent.getKey()+"="+ent.getValue());
 		  }
@@ -322,7 +322,7 @@ public class CommandLine
 		     }
 		  }
 		  
-		  Vector<HashMap<String,String>> results=new Vector<HashMap<String,String>>();
+		  Vector<HashMap<String,ByteIterator>> results=new Vector<HashMap<String,ByteIterator>>();
 		  int ret=db.scan(table,tokens[1],Integer.parseInt(tokens[2]),fields,results);
 		  System.out.println("Return code: "+ret);
 		  int record=0;
@@ -334,10 +334,10 @@ public class CommandLine
 		  {
 		     System.out.println("--------------------------------");
 		  }
-		  for (HashMap<String,String> result : results)
+		  for (HashMap<String,ByteIterator> result : results)
 		  {
 		     System.out.println("Record "+(record++));
-		     for (Map.Entry<String,String> ent : result.entrySet())
+		     for (Map.Entry<String,ByteIterator> ent : result.entrySet())
 		     {
 			System.out.println(ent.getKey()+"="+ent.getValue());
 		     }
@@ -353,12 +353,12 @@ public class CommandLine
 	       }
 	       else 
 	       {
-		  HashMap<String,String> values=new HashMap<String,String>();
+		  HashMap<String,ByteIterator> values=new HashMap<String,ByteIterator>();
 
 		  for (int i=2; i<tokens.length; i++)
 		  {
 		     String[] nv=tokens[i].split("=");
-		     values.put(nv[0],nv[1]);
+		     values.put(nv[0],new StringByteIterator(nv[1]));
 		  }
 
 		  int ret=db.update(table,tokens[1],values);
@@ -373,12 +373,12 @@ public class CommandLine
 	       }
 	       else 
 	       {
-		  HashMap<String,String> values=new HashMap<String,String>();
+		  HashMap<String,ByteIterator> values=new HashMap<String,ByteIterator>();
 
 		  for (int i=2; i<tokens.length; i++)
 		  {
 		     String[] nv=tokens[i].split("=");
-		     values.put(nv[0],nv[1]);
+		     values.put(nv[0],new StringByteIterator(nv[1]));
 		  }
 
 		  int ret=db.insert(table,tokens[1],values);
diff --git a/src/com/yahoo/ycsb/DB.java b/src/com/yahoo/ycsb/DB.java
index d790d131e2e2c2aa119a79c91435c33703b41331..91a695f140623729b7a7dbd8b8ebf087ff91ba9f 100644
--- a/src/com/yahoo/ycsb/DB.java
+++ b/src/com/yahoo/ycsb/DB.java
@@ -90,7 +90,7 @@ public abstract class DB
 	 * @param result A HashMap of field/value pairs for the result
 	 * @return Zero on success, a non-zero error code on error or "not found".
 	 */
-	public abstract int read(String table, String key, Set<String> fields, HashMap<String,String> result);
+	public abstract int read(String table, String key, Set<String> fields, HashMap<String,ByteIterator> result);
 
 	/**
 	 * Perform a range scan for a set of records in the database. Each field/value pair from the result will be stored in a HashMap.
@@ -102,7 +102,7 @@ public abstract class DB
 	 * @param result A Vector of HashMaps, where each HashMap is a set field/value pairs for one record
 	 * @return Zero on success, a non-zero error code on error.  See this class's description for a discussion of error codes.
 	 */
-	public abstract int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,String>> result);
+	public abstract int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,ByteIterator>> result);
 	
 	/**
 	 * Update a record in the database. Any field/value pairs in the specified values HashMap will be written into the record with the specified
@@ -113,7 +113,7 @@ public abstract class DB
 	 * @param values A HashMap of field/value pairs to update in the record
 	 * @return Zero on success, a non-zero error code on error.  See this class's description for a discussion of error codes.
 	 */
-	public abstract int update(String table, String key, HashMap<String,String> values);
+	public abstract int update(String table, String key, HashMap<String,ByteIterator> values);
 
 	/**
 	 * Insert a record in the database. Any field/value pairs in the specified values HashMap will be written into the record with the specified
@@ -124,7 +124,7 @@ public abstract class DB
 	 * @param values A HashMap of field/value pairs to insert in the record
 	 * @return Zero on success, a non-zero error code on error.  See this class's description for a discussion of error codes.
 	 */
-	public abstract int insert(String table, String key, HashMap<String,String> values);
+	public abstract int insert(String table, String key, HashMap<String,ByteIterator> values);
 
 	/**
 	 * Delete a record from the database. 
diff --git a/src/com/yahoo/ycsb/DBWrapper.java b/src/com/yahoo/ycsb/DBWrapper.java
index 8ca7a89fbc5c7197dea71abfba0d26ea7e1fd395..4516e7b0adf39e8fa733a7e7cb20aa708fbda0e8 100644
--- a/src/com/yahoo/ycsb/DBWrapper.java
+++ b/src/com/yahoo/ycsb/DBWrapper.java
@@ -81,12 +81,12 @@ public class DBWrapper extends DB
 	 * @param result A HashMap of field/value pairs for the result
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int read(String table, String key, Set<String> fields, HashMap<String,String> result)
+	public int read(String table, String key, Set<String> fields, HashMap<String,ByteIterator> result)
 	{
-		long st=System.currentTimeMillis();
+		long st=System.nanoTime();
 		int res=_db.read(table,key,fields,result);
-		long en=System.currentTimeMillis();
-		_measurements.measure("READ",(int)(en-st));
+		long en=System.nanoTime();
+		_measurements.measure("READ",(int)((en-st)/1000));
 		_measurements.reportReturnCode("READ",res);
 		return res;
 	}
@@ -101,12 +101,12 @@ public class DBWrapper extends DB
 	 * @param result A Vector of HashMaps, where each HashMap is a set field/value pairs for one record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,String>> result)
+	public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,ByteIterator>> result)
 	{
-		long st=System.currentTimeMillis();
+		long st=System.nanoTime();
 		int res=_db.scan(table,startkey,recordcount,fields,result);
-		long en=System.currentTimeMillis();
-		_measurements.measure("SCAN",(int)(en-st));
+		long en=System.nanoTime();
+		_measurements.measure("SCAN",(int)((en-st)/1000));
 		_measurements.reportReturnCode("SCAN",res);
 		return res;
 	}
@@ -120,12 +120,12 @@ public class DBWrapper extends DB
 	 * @param values A HashMap of field/value pairs to update in the record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int update(String table, String key, HashMap<String,String> values)
+	public int update(String table, String key, HashMap<String,ByteIterator> values)
 	{
-		long st=System.currentTimeMillis();
+		long st=System.nanoTime();
 		int res=_db.update(table,key,values);
-		long en=System.currentTimeMillis();
-		_measurements.measure("UPDATE",(int)(en-st));
+		long en=System.nanoTime();
+		_measurements.measure("UPDATE",(int)((en-st)/1000));
 		_measurements.reportReturnCode("UPDATE",res);
 		return res;
 	}
@@ -139,12 +139,12 @@ public class DBWrapper extends DB
 	 * @param values A HashMap of field/value pairs to insert in the record
 	 * @return Zero on success, a non-zero error code on error
 	 */
-	public int insert(String table, String key, HashMap<String,String> values)
+	public int insert(String table, String key, HashMap<String,ByteIterator> values)
 	{
-		long st=System.currentTimeMillis();
+		long st=System.nanoTime();
 		int res=_db.insert(table,key,values);
-		long en=System.currentTimeMillis();
-		_measurements.measure("INSERT",(int)(en-st));
+		long en=System.nanoTime();
+		_measurements.measure("INSERT",(int)((en-st)/1000));
 		_measurements.reportReturnCode("INSERT",res);
 		return res;
 	}
@@ -158,10 +158,10 @@ public class DBWrapper extends DB
 	 */
 	public int delete(String table, String key)
 	{
-		long st=System.currentTimeMillis();
+		long st=System.nanoTime();
 		int res=_db.delete(table,key);
-		long en=System.currentTimeMillis();
-		_measurements.measure("DELETE",(int)(en-st));
+		long en=System.nanoTime();
+		_measurements.measure("DELETE",(int)((en-st)/1000));
 		_measurements.reportReturnCode("DELETE",res);
 		return res;
 	}
diff --git a/src/com/yahoo/ycsb/InputStreamByteIterator.java b/src/com/yahoo/ycsb/InputStreamByteIterator.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e90496cb3abff047bc5c15e888c466d1f4cfa8f
--- /dev/null
+++ b/src/com/yahoo/ycsb/InputStreamByteIterator.java
@@ -0,0 +1,55 @@
+/**                                                                                                                                                                                
+ * Copyright (c) 2010 Yahoo! Inc. 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;
+
+import java.io.InputStream;
+
+public class InputStreamByteIterator extends ByteIterator {
+	long len;
+	InputStream ins;
+	long off;
+	
+	public InputStreamByteIterator(InputStream ins, long len) {
+		this.len = len;
+		this.ins = ins;
+		off = 0;
+	}
+	
+	@Override
+	public boolean hasNext() {
+		return off < len;
+	}
+
+	@Override
+	public byte nextByte() {
+		int ret;
+		try {
+			ret = ins.read();
+		} catch(Exception e) {
+			throw new IllegalStateException(e);
+		}
+		if(ret == -1) { throw new IllegalStateException("Past EOF!"); }
+		off++;
+		return (byte)ret;
+	}
+
+	@Override
+	public long bytesLeft() {
+		return len - off;
+	}
+
+}
diff --git a/src/com/yahoo/ycsb/RandomByteIterator.java b/src/com/yahoo/ycsb/RandomByteIterator.java
new file mode 100644
index 0000000000000000000000000000000000000000..99239f859fb8011e663af50acaa985b09a6d0586
--- /dev/null
+++ b/src/com/yahoo/ycsb/RandomByteIterator.java
@@ -0,0 +1,84 @@
+/**                                                                                                                                                                                
+ * Copyright (c) 2010 Yahoo! Inc. 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;
+
+public class RandomByteIterator extends ByteIterator {
+	long len;
+	long off;
+	int buf_off;
+	byte[] buf;
+	
+	@Override
+	public boolean hasNext() {
+		return (off + buf_off) < len;
+	}
+
+	private void fillBytesImpl(byte[] buf, int base) {
+		int bytes = Utils.random().nextInt();
+		try {
+			buf[base+0] = (byte)(((bytes      ) & 31) + ' ');
+			buf[base+1] = (byte)(((bytes >> 5 ) & 31) + ' ');
+			buf[base+2] = (byte)(((bytes >> 10) & 31) + ' ');
+			buf[base+3] = (byte)(((bytes >> 15) & 31) + ' ');
+			buf[base+4] = (byte)(((bytes >> 20) & 31) + ' ');
+			buf[base+5] = (byte)(((bytes >> 25) & 31) + ' ');
+		} catch (ArrayIndexOutOfBoundsException e) { /* ignore it */ }
+	}
+	
+	private void fillBytes() {
+		if(buf_off ==  buf.length) {
+			fillBytesImpl(buf, 0);
+			buf_off = 0;
+			off += buf.length;
+		}
+	}
+	
+	public RandomByteIterator(long len) {
+		this.len = len;
+		this.buf = new byte[6];
+		this.buf_off = buf.length;
+		fillBytes();
+		this.off = 0;
+	}
+
+	public byte nextByte() {
+		fillBytes();
+		buf_off++;
+		return buf[buf_off-1];
+	}
+	@Override
+	public int nextBuf(byte[] b, int buf_off) {
+		int ret;
+		if(len - off < b.length - buf_off) {
+			ret = (int)(len - off);
+		} else {
+			ret = b.length - buf_off;
+		}
+		int i;
+		for(i = 0; i < ret; i+=6) {
+			fillBytesImpl(b, i+buf_off);
+		}
+		off+=ret;
+		return ret + buf_off;
+	}
+	
+	
+	@Override
+	public long bytesLeft() {
+		return len - off;
+	}
+}
diff --git a/src/com/yahoo/ycsb/StringByteIterator.java b/src/com/yahoo/ycsb/StringByteIterator.java
new file mode 100644
index 0000000000000000000000000000000000000000..84465cba3ef0482bea716c3daf2cf7ca45463961
--- /dev/null
+++ b/src/com/yahoo/ycsb/StringByteIterator.java
@@ -0,0 +1,108 @@
+/**                                                                                                                                                                                
+ * Copyright (c) 2010 Yahoo! Inc. 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;
+
+import java.util.Map;
+import java.util.HashMap;
+
+public class StringByteIterator extends ByteIterator {
+	String str;
+	int off;
+
+	/**
+	 * Put all of the entries of one map into the other, converting
+	 * String values into ByteIterators.
+	 */
+	public static void putAllAsByteIterators(Map<String, ByteIterator> out, Map<String, String> in) {
+	       for(String s: in.keySet()) { out.put(s, new StringByteIterator(in.get(s))); }
+	} 
+
+	/**
+	 * Put all of the entries of one map into the other, converting
+	 * ByteIterator values into Strings.
+	 */
+	public static void putAllAsStrings(Map<String, String> out, Map<String, ByteIterator> in) {
+	       for(String s: in.keySet()) { out.put(s, in.get(s).toString()); }
+	} 
+
+	/**
+	 * Create a copy of a map, converting the values from Strings to
+	 * StringByteIterators.
+	 */
+	public static HashMap<String, ByteIterator> getByteIteratorMap(Map<String, String> m) {
+		HashMap<String, ByteIterator> ret =
+			new HashMap<String,ByteIterator>();
+
+		for(String s: m.keySet()) {
+			ret.put(s, new StringByteIterator(m.get(s)));
+		}
+		return ret;
+	}
+
+	/**
+	 * Create a copy of a map, converting the values from
+	 * StringByteIterators to Strings.
+	 */
+	public static HashMap<String, String> getStringMap(Map<String, ByteIterator> m) {
+		HashMap<String, String> ret = new HashMap<String,String>();
+
+		for(String s: m.keySet()) {
+			ret.put(s, m.get(s).toString());;
+		}
+		return ret;
+	}
+
+	public StringByteIterator(String s) {
+		this.str = s;
+		this.off = 0;
+	}
+	@Override
+	public boolean hasNext() {
+		return off < str.length();
+	}
+
+	@Override
+	public byte nextByte() {
+		byte ret = (byte)str.charAt(off);
+		off++;
+		return ret;
+	}
+
+	@Override
+	public long bytesLeft() {
+		return str.length() - off;
+	}
+
+	/**
+	 * Specialization of general purpose toString() to avoid unnecessary
+	 * copies.
+	 * <p>
+	 * Creating a new StringByteIterator, then calling toString()
+	 * yields the original String object, and does not perform any copies
+	 * or String conversion operations.
+	 * </p>
+	 */
+	@Override
+	public String toString() {
+		if(off > 0) {
+			return super.toString();
+		} else {
+			return str;
+		}
+	}
+}
diff --git a/src/com/yahoo/ycsb/Utils.java b/src/com/yahoo/ycsb/Utils.java
index f94ebc0d2d84d63d5122b5567d9b94ba617189de..f49bc0f5c03cd1b3cd7993d9d97ba619cc5cde37 100644
--- a/src/com/yahoo/ycsb/Utils.java
+++ b/src/com/yahoo/ycsb/Utils.java
@@ -24,8 +24,17 @@ import java.util.Random;
  */
 public class Utils
 {
-	static Random random=new Random();
-	
+  private static final Random rand = new Random();
+  private static final ThreadLocal<Random> rng = new ThreadLocal<Random>();
+
+  public static Random random() {
+    Random ret = rng.get();
+    if(ret == null) {
+      ret = new Random(rand.nextLong());
+      rng.set(ret);
+    }
+    return ret;
+  }
       /**
        * Generate a random ASCII string of a given length.
        */
@@ -34,7 +43,7 @@ public class Utils
 	 int interval='~'-' '+1;
 	
         byte []buf = new byte[length];
-        random.nextBytes(buf);
+        random().nextBytes(buf);
         for (int i = 0; i < length; i++) {
           if (buf[i] < 0) {
             buf[i] = (byte)((-buf[i] % interval) + ' ');
@@ -48,9 +57,9 @@ public class Utils
       /**
        * Hash an integer value.
        */
-      public static int hash(int val)
+      public static long hash(long val)
       {
-	 return FNVhash32(val);
+	 return FNVhash64(val);
       }
 	
       public static final int FNV_offset_basis_32=0x811c9dc5;
diff --git a/src/com/yahoo/ycsb/generator/ConstantIntegerGenerator.java b/src/com/yahoo/ycsb/generator/ConstantIntegerGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..94dd3a6ae414f0ef40d20ba5f87d448a2af30a27
--- /dev/null
+++ b/src/com/yahoo/ycsb/generator/ConstantIntegerGenerator.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2010 Yahoo! Inc. 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;
+
+/**
+ * A trivial integer generator that always returns the same value.
+ * 
+ * @author sears
+ *
+ */
+public class ConstantIntegerGenerator extends IntegerGenerator {
+	private final int i;
+	/**
+	 * @param i The integer that this generator will always return.
+	 */
+	public ConstantIntegerGenerator(int i) {
+		this.i = i;
+	}
+
+	@Override
+	public int nextInt() {
+		return i;
+	}
+
+	@Override
+	public double mean() {
+		return i;
+	}
+
+}
diff --git a/src/com/yahoo/ycsb/generator/CounterGenerator.java b/src/com/yahoo/ycsb/generator/CounterGenerator.java
index 70ce1b045075b209f14b2298d8437e8d01b2d68c..df37b2398c5f0f46e886d7df7367398f68d86b90 100644
--- a/src/com/yahoo/ycsb/generator/CounterGenerator.java
+++ b/src/com/yahoo/ycsb/generator/CounterGenerator.java
@@ -17,33 +17,41 @@
 
 package com.yahoo.ycsb.generator;
 
+import java.util.concurrent.atomic.AtomicInteger;
+
 /**
  * Generates a sequence of integers 0, 1, ...
  */
 public class CounterGenerator extends IntegerGenerator
 {
-	int counter;
+	final AtomicInteger counter;
 
 	/**
 	 * Create a counter that starts at countstart
 	 */
 	public CounterGenerator(int countstart)
 	{
-		counter=countstart;
-		setLastInt(countstart-1);
+		counter=new AtomicInteger(countstart);
+		setLastInt(counter.get()-1);
 	}
 	
 	/**
 	 * If the generator returns numeric (integer) values, return the next value as an int. Default is to return -1, which
 	 * is appropriate for generators that do not return numeric values.
 	 */
-	public synchronized int nextInt() 
+	public int nextInt() 
 	{
-		int lastint=counter;
-		counter++;
-		setLastInt(lastint);
-		return lastint;
+		int ret = counter.getAndIncrement();
+		setLastInt(ret);
+		return ret;
+	}
+	@Override
+	public int lastInt()
+	{
+	                return counter.get() - 1;
+	}
+	@Override
+	public double mean() {
+		throw new UnsupportedOperationException("Can't compute mean of non-stationary distribution!");
 	}
-
-
 }
diff --git a/src/com/yahoo/ycsb/generator/DiscreteGenerator.java b/src/com/yahoo/ycsb/generator/DiscreteGenerator.java
index 087312c03519bbc50ef69f04f63288125c3c0b97..c28f3ae771e1bbe667902e925bf0a16f0bdf8fe3 100644
--- a/src/com/yahoo/ycsb/generator/DiscreteGenerator.java
+++ b/src/com/yahoo/ycsb/generator/DiscreteGenerator.java
@@ -20,6 +20,7 @@ package com.yahoo.ycsb.generator;
 import java.util.Vector;
 import java.util.Random;
 
+import com.yahoo.ycsb.Utils;
 import com.yahoo.ycsb.WorkloadException;
 
 /**
@@ -40,13 +41,11 @@ public class DiscreteGenerator extends Generator
 	}
 
 	Vector<Pair> _values;
-	Random _random;
 	String _lastvalue;
 
 	public DiscreteGenerator()
 	{
 		_values=new Vector<Pair>();
-		_random=new Random();
 		_lastvalue=null;
 	}
 
@@ -62,7 +61,7 @@ public class DiscreteGenerator extends Generator
 			sum+=p._weight;
 		}
 
-		double val=_random.nextDouble();
+		double val=Utils.random().nextDouble();
 
 		for (Pair p : _values)
 		{
diff --git a/src/com/yahoo/ycsb/generator/ExponentialGenerator.java b/src/com/yahoo/ycsb/generator/ExponentialGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..de1a2760c4b02b308666dbc7ceaefb9cc8805cfd
--- /dev/null
+++ b/src/com/yahoo/ycsb/generator/ExponentialGenerator.java
@@ -0,0 +1,102 @@
+/**                                                                                                                                                                                
+ * Copyright (c) 2011 Yahoo! Inc. 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.Random;
+
+import com.yahoo.ycsb.Utils;
+
+/**
+ * A generator of an exponential distribution. It produces a sequence
+ * of time intervals (integers) according to an exponential
+ * distribution.  Smaller intervals are more frequent than larger
+ * ones, and there is no bound on the length of an interval.  When you
+ * construct an instance of this class, you specify a parameter gamma,
+ * which corresponds to the rate at which events occur.
+ * Alternatively, 1/gamma is the average length of an interval.
+ */
+public class ExponentialGenerator extends IntegerGenerator
+{
+    // What percentage of the readings should be within the most recent exponential.frac portion of the dataset?
+    public static final String EXPONENTIAL_PERCENTILE_PROPERTY="exponential.percentile";
+    public static final String EXPONENTIAL_PERCENTILE_DEFAULT="95";
+
+    // What fraction of the dataset should be accessed exponential.percentile of the time?
+    public static final String EXPONENTIAL_FRAC_PROPERTY = "exponential.frac";
+    public static final String EXPONENTIAL_FRAC_DEFAULT  = "0.8571428571";  // 1/7
+
+	/**
+	 * The exponential constant to use.
+	 */
+	double _gamma;	
+
+	/******************************* Constructors **************************************/
+
+	/**
+	 * Create an exponential generator with a mean arrival rate of
+	 * gamma.  (And half life of 1/gamma).
+	 */
+	public ExponentialGenerator(double mean)
+	{
+		_gamma = 1.0/mean;
+	}
+	public ExponentialGenerator(double percentile, double range)
+	{
+		_gamma = -Math.log(1.0-percentile/100.0) / range;  //1.0/mean;
+	}
+
+	/****************************************************************************************/
+	
+	/** 
+	 * Generate the next item. this distribution will be skewed toward lower integers; e.g. 0 will
+	 * be the most popular, 1 the next most popular, etc.
+	 * @param itemcount The number of items in the distribution.
+	 * @return The next item in the sequence.
+	 */
+	@Override
+	public int nextInt()
+	{
+		return (int)nextLong();
+	}
+
+	/**
+	 * Generate the next item as a long.
+	 * 
+	 * @param itemcount The number of items in the distribution.
+	 * @return The next item in the sequence.
+	 */
+	public long nextLong()
+	{
+		return (long) (-Math.log(Utils.random().nextDouble()) / _gamma);
+	}
+
+	@Override
+	public double mean() {
+		return 1.0/_gamma;
+	}
+    public static void main(String args[]) {
+        ExponentialGenerator e = new ExponentialGenerator(90, 100);
+        int j = 0;
+        for(int i = 0; i < 1000; i++) {
+            if(e.nextInt() < 100) {
+                j++;
+            }
+        }
+        System.out.println("Got " + j + " hits.  Expect 900");
+    }
+}
diff --git a/src/com/yahoo/ycsb/generator/HistogramGenerator.java b/src/com/yahoo/ycsb/generator/HistogramGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..aba42c47b0c060a92b667c7d6808f3b608c37dac
--- /dev/null
+++ b/src/com/yahoo/ycsb/generator/HistogramGenerator.java
@@ -0,0 +1,114 @@
+/**
+ * Copyright (c) 2010 Yahoo! Inc. 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.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Random;
+
+import com.yahoo.ycsb.Utils;
+import com.yahoo.ycsb.generator.IntegerGenerator;
+
+/**
+ * Generate integers according to a histogram distribution.  The histogram
+ * buckets are of width one, but the values are multiplied by a block size.
+ * Therefore, instead of drawing sizes uniformly at random within each
+ * bucket, we always draw the largest value in the current bucket, so the value
+ * drawn is always a multiple of block_size.
+ * 
+ * The minimum value this distribution returns is block_size (not zero).
+ * 
+ * Modified Nov 19 2010 by sears
+ * 
+ * @author snjones
+ *
+ */
+public class HistogramGenerator extends IntegerGenerator {
+
+	long block_size;
+	long[] buckets;
+	long area;
+	long weighted_area = 0;
+	double mean_size = 0;
+	
+	public HistogramGenerator(String histogramfile) throws IOException {
+	BufferedReader in = new BufferedReader(new FileReader(histogramfile));
+	String str;
+	String[] line;
+	
+	ArrayList<Integer> a = new ArrayList<Integer>();
+
+	str = in.readLine();
+	if(str == null) {
+		throw new IOException("Empty input file!\n");
+	}
+	line = str.split("\t");
+	if(line[0].compareTo("BlockSize") != 0) {
+		throw new IOException("First line of histogram is not the BlockSize!\n");
+	}
+	block_size = Integer.parseInt(line[1]);
+	
+	while((str = in.readLine()) != null){
+		// [0] is the bucket, [1] is the value
+		line = str.split("\t");
+		
+		a.add(Integer.parseInt(line[0]), Integer.parseInt(line[1]));
+	}
+	buckets = new long[a.size()];
+	for(int i = 0; i < a.size(); i++) {
+		buckets[i] = a.get(i);
+	}
+
+	in.close();
+	init();
+	}
+
+	public HistogramGenerator(long[] buckets, int block_size) {
+		this.block_size = block_size;
+		this.buckets = buckets;
+		init();
+	}
+	private void init() {
+		for(int i = 0; i < buckets.length; i++) {
+			area += buckets[i];
+			weighted_area = i * buckets[i];
+		}
+		// calculate average file size
+		mean_size = ((double)block_size) * ((double)weighted_area) / (double)(area);
+	}
+
+	@Override
+	public int nextInt() {
+		int number = Utils.random().nextInt((int)area);
+		int i;
+		
+		for(i = 0; i < (buckets.length - 1); i++){
+			number -= buckets[i];
+			if(number <= 0){
+				return (int)((i+1)*block_size);
+			}
+		}
+		
+		return (int)(i * block_size);
+	}
+
+	@Override
+	public double mean() {
+		return mean_size;
+	}
+}
diff --git a/src/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java b/src/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java
index dd12db7acece45083a800dbd57d4815eb486ce12..969ae7706d781b48e50f2289db602eb666a761d9 100644
--- a/src/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java
+++ b/src/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java
@@ -18,6 +18,8 @@ package com.yahoo.ycsb.generator;
 
 import java.util.Random;
 
+import com.yahoo.ycsb.Utils;
+
 /**
  * Generate integers resembling a hotspot distribution where x% of operations
  * access y% of data items. The parameters specify the bounds for the numbers,
@@ -37,7 +39,6 @@ public class HotspotIntegerGenerator extends IntegerGenerator {
   private final int coldInterval;
   private final double hotsetFraction;
   private final double hotOpnFraction;
-  private final Random random;
   
   /**
    * Create a generator for Hotspot distributions.
@@ -71,12 +72,12 @@ public class HotspotIntegerGenerator extends IntegerGenerator {
     this.hotInterval = (int)(interval * hotsetFraction);
     this.coldInterval = interval - hotInterval;
     this.hotOpnFraction = hotOpnFraction;
-    random = new Random();
   }
   
   @Override
   public int nextInt() {
     int value = 0;
+    Random random = Utils.random();
     if (random.nextDouble() < hotOpnFraction) {
       // Choose a value from the hot set.
       value = lowerBound + random.nextInt(hotInterval);
@@ -115,5 +116,9 @@ public class HotspotIntegerGenerator extends IntegerGenerator {
   public double getHotOpnFraction() {
     return hotOpnFraction;
   }
-
+  @Override
+  public double mean() {
+    return hotOpnFraction * (lowerBound + hotInterval/2.0)
+      + (1 - hotOpnFraction) * (lowerBound + hotInterval + coldInterval/2.0);
+  }
 }
diff --git a/src/com/yahoo/ycsb/generator/IntegerGenerator.java b/src/com/yahoo/ycsb/generator/IntegerGenerator.java
index 8268f14cfd7a79663bc23f1304289fc89ba12b9c..13d36cd1f1f423e7cd97b36789e2e02152d1ef09 100644
--- a/src/com/yahoo/ycsb/generator/IntegerGenerator.java
+++ b/src/com/yahoo/ycsb/generator/IntegerGenerator.java
@@ -31,7 +31,7 @@ public abstract class IntegerGenerator extends Generator
 	 * Set the last value generated. IntegerGenerator subclasses must use this call
 	 * to properly set the last string value, or the lastString() and lastInt() calls won't work.
 	 */
-	public void setLastInt(int last)
+	protected void setLastInt(int last)
 	{
 		lastint=last;
 	}
@@ -54,9 +54,10 @@ public abstract class IntegerGenerator extends Generator
 	 * Calling lastString() should not advance the distribution or have any side effects. If nextString() has not yet 
 	 * been called, lastString() should return something reasonable.
 	 */
+	@Override
 	public String lastString()
 	{
-		return ""+lastint;
+		return ""+lastInt();
 	}
 	
 	/**
@@ -67,4 +68,8 @@ public abstract class IntegerGenerator extends Generator
 	{
 		return lastint;
 	}
+	/**
+	 * Return the expected value (mean) of the values this generator will return.
+	 */
+	public abstract double mean();
 }
diff --git a/src/com/yahoo/ycsb/generator/ScrambledZipfianGenerator.java b/src/com/yahoo/ycsb/generator/ScrambledZipfianGenerator.java
index 0f5731b3e25d2f6ab0b43efa39b0b881527272fb..8b62c4c2bacef2c2c094c9c54b6a55e8ed8e7af9 100644
--- a/src/com/yahoo/ycsb/generator/ScrambledZipfianGenerator.java
+++ b/src/com/yahoo/ycsb/generator/ScrambledZipfianGenerator.java
@@ -126,4 +126,12 @@ public class ScrambledZipfianGenerator extends IntegerGenerator
 			System.out.println(""+gen.nextInt());
 		}
 	}
+
+	/**
+	 * since the values are scrambled (hopefully uniformly), the mean is simply the middle of the range.
+	 */
+	@Override
+	public double mean() {
+		return ((double)(((long)_min) +(long)_max))/2.0;
+	}
 }
diff --git a/src/com/yahoo/ycsb/generator/SkewedLatestGenerator.java b/src/com/yahoo/ycsb/generator/SkewedLatestGenerator.java
index 1b86097ebf996f02e2d62282ee2ac3f54de1e304..376eb7775c6b7cf6c44549728d4a03a4d47916b6 100644
--- a/src/com/yahoo/ycsb/generator/SkewedLatestGenerator.java
+++ b/src/com/yahoo/ycsb/generator/SkewedLatestGenerator.java
@@ -28,7 +28,7 @@ public class SkewedLatestGenerator extends IntegerGenerator
 	public SkewedLatestGenerator(CounterGenerator basis)
 	{
 		_basis=basis;
-		_zipfian=new ZipfianGenerator(Integer.parseInt(_basis.lastString()));
+		_zipfian=new ZipfianGenerator(_basis.lastInt());
 		nextInt();
 	}
 
@@ -37,7 +37,7 @@ public class SkewedLatestGenerator extends IntegerGenerator
 	 */
 	public int nextInt()
 	{
-		int max=Integer.parseInt(_basis.lastString());
+		int max=_basis.lastInt();
 		int nextint=max-_zipfian.nextInt(max);
 		setLastInt(nextint);
 		return nextint;
@@ -53,4 +53,9 @@ public class SkewedLatestGenerator extends IntegerGenerator
 
 	}
 
+	@Override
+	public double mean() {
+		throw new UnsupportedOperationException("Can't compute mean of non-stationary distribution!");
+	}
+
 }
diff --git a/src/com/yahoo/ycsb/generator/UniformIntegerGenerator.java b/src/com/yahoo/ycsb/generator/UniformIntegerGenerator.java
index 74ebba09616e37c0cb8020d8ac0922f7bd762382..fa6af1316ca3d156653d9b362f1f59debd451a97 100644
--- a/src/com/yahoo/ycsb/generator/UniformIntegerGenerator.java
+++ b/src/com/yahoo/ycsb/generator/UniformIntegerGenerator.java
@@ -19,12 +19,13 @@ package com.yahoo.ycsb.generator;
 
 import java.util.Random;
 
+import com.yahoo.ycsb.Utils;
+
 /**
  * Generates integers randomly uniform from an interval.
  */
 public class UniformIntegerGenerator extends IntegerGenerator 
 {
-	Random _random;
 	int _lb,_ub,_interval;
 	
 	/**
@@ -35,7 +36,6 @@ public class UniformIntegerGenerator extends IntegerGenerator
 	 */
 	public UniformIntegerGenerator(int lb, int ub)
 	{
-		_random=new Random();
 		_lb=lb;
 		_ub=ub;
 		_interval=_ub-_lb+1;
@@ -44,10 +44,14 @@ public class UniformIntegerGenerator extends IntegerGenerator
 	@Override
 	public int nextInt() 
 	{
-		int ret=_random.nextInt(_interval)+_lb;
+		int ret=Utils.random().nextInt(_interval)+_lb;
 		setLastInt(ret);
 		
 		return ret;
 	}
 
+	@Override
+	public double mean() {
+		return ((double)((long)(_lb + (long)_ub))) / 2.0;
+	}
 }
diff --git a/src/com/yahoo/ycsb/generator/ZipfianGenerator.java b/src/com/yahoo/ycsb/generator/ZipfianGenerator.java
index cc0ade83dedda42fbd7f3cd5dea1c1fb37ffa244..8a70f0869a16c7d2776072c1b6c4ed2e94e38e27 100644
--- a/src/com/yahoo/ycsb/generator/ZipfianGenerator.java
+++ b/src/com/yahoo/ycsb/generator/ZipfianGenerator.java
@@ -19,6 +19,8 @@ package com.yahoo.ycsb.generator;
 
 import java.util.Random;
 
+import com.yahoo.ycsb.Utils;
+
 /**
  * A generator of a zipfian distribution. It produces a sequence of items, such that some items are more popular than others, according
  * to a zipfian distribution. When you construct an instance of this class, you specify the number of items in the set to draw from, either
@@ -61,8 +63,6 @@ public class ZipfianGenerator extends IntegerGenerator
 	 */
 	double alpha,zetan,eta,theta,zeta2theta;
 	
-	Random random;
-
 	/**
 	 * The number of items used to compute zetan the last time.
 	 */
@@ -136,8 +136,6 @@ public class ZipfianGenerator extends IntegerGenerator
 		base=min;
 		zipfianconstant=_zipfianconstant;
 
-		random=new Random();	 
-
 		theta=zipfianconstant;
 
 		zeta2theta=zeta(2,theta);
@@ -273,7 +271,7 @@ public class ZipfianGenerator extends IntegerGenerator
 			}
 		}
 
-		double u=random.nextDouble();
+		double u=Utils.random().nextDouble();
 		double uz=u*zetan;
 
 		if (uz<1.0)
@@ -316,4 +314,12 @@ public class ZipfianGenerator extends IntegerGenerator
 	{
 		new ZipfianGenerator(ScrambledZipfianGenerator.ITEM_COUNT);
 	}
+
+	/**
+	 * @todo Implement ZipfianGenerator.mean()
+	 */
+	@Override
+	public double mean() {
+		throw new UnsupportedOperationException("@todo implement ZipfianGenerator.mean()");
+	}
 }
diff --git a/src/com/yahoo/ycsb/measurements/OneMeasurementHistogram.java b/src/com/yahoo/ycsb/measurements/OneMeasurementHistogram.java
index a97d925dc533d801b4f12522fa14ad8a14d5254b..2cba955a2a3c926f1d7b719c26b9696562522a08 100644
--- a/src/com/yahoo/ycsb/measurements/OneMeasurementHistogram.java
+++ b/src/com/yahoo/ycsb/measurements/OneMeasurementHistogram.java
@@ -86,13 +86,13 @@ public class OneMeasurementHistogram extends OneMeasurement
 	 */
 	public synchronized void measure(int latency)
 	{
-		if (latency>=_buckets)
+		if (latency/1000>=_buckets)
 		{
 			histogramoverflow++;
 		}
 		else
 		{
-			histogram[latency]++;
+			histogram[latency/1000]++;
 		}
 		operations++;
 		totallatency+=latency;
@@ -115,9 +115,9 @@ public class OneMeasurementHistogram extends OneMeasurement
   public void exportMeasurements(MeasurementsExporter exporter) throws IOException
   {
     exporter.write(getName(), "Operations", operations);
-    exporter.write(getName(), "AverageLatency(ms)", (((double)totallatency)/((double)operations)));
-    exporter.write(getName(), "MinLatency(ms)", min);
-    exporter.write(getName(), "MaxLatency(ms)", max);
+    exporter.write(getName(), "AverageLatency(us)", (((double)totallatency)/((double)operations)));
+    exporter.write(getName(), "MinLatency(us)", min);
+    exporter.write(getName(), "MaxLatency(us)", max);
     
     int opcounter=0;
     boolean done95th=false;
@@ -159,7 +159,7 @@ public class OneMeasurementHistogram extends OneMeasurement
 		double report=((double)windowtotallatency)/((double)windowoperations);
 		windowtotallatency=0;
 		windowoperations=0;
-		return "["+getName()+" AverageLatency(ms)="+d.format(report)+"]";
+		return "["+getName()+" AverageLatency(us)="+d.format(report)+"]";
 	}
 
 }
diff --git a/src/com/yahoo/ycsb/measurements/OneMeasurementTimeSeries.java b/src/com/yahoo/ycsb/measurements/OneMeasurementTimeSeries.java
index 19415ba1863085a9ea7deebf7b738c33937ea26a..25c77b76740feaed3bf134c78b249e4e9146a827 100644
--- a/src/com/yahoo/ycsb/measurements/OneMeasurementTimeSeries.java
+++ b/src/com/yahoo/ycsb/measurements/OneMeasurementTimeSeries.java
@@ -132,9 +132,9 @@ public class OneMeasurementTimeSeries extends OneMeasurement
     checkEndOfUnit(true);
 
     exporter.write(getName(), "Operations", operations);
-    exporter.write(getName(), "AverageLatency(ms)", (((double)totallatency)/((double)operations)));
-    exporter.write(getName(), "MinLatency(ms)", min);
-    exporter.write(getName(), "MaxLatency(ms)", max);
+    exporter.write(getName(), "AverageLatency(us)", (((double)totallatency)/((double)operations)));
+    exporter.write(getName(), "MinLatency(us)", min);
+    exporter.write(getName(), "MaxLatency(us)", max);
 
     //TODO: 95th and 99th percentile latency
 
@@ -173,7 +173,7 @@ public class OneMeasurementTimeSeries extends OneMeasurement
 		double report=((double)windowtotallatency)/((double)windowoperations);
 		windowtotallatency=0;
 		windowoperations=0;
-		return "["+getName()+" AverageLatency(ms)="+d.format(report)+"]";
+		return "["+getName()+" AverageLatency(us)="+d.format(report)+"]";
 	}
 
 }
diff --git a/src/com/yahoo/ycsb/workloads/ConstantOccupancyWorkload.java b/src/com/yahoo/ycsb/workloads/ConstantOccupancyWorkload.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a5e7d025d93e21be5ebb099965437abda3c7cd8
--- /dev/null
+++ b/src/com/yahoo/ycsb/workloads/ConstantOccupancyWorkload.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) 2010 Yahoo! Inc. 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.workloads;
+
+import java.util.Properties;
+
+import com.yahoo.ycsb.WorkloadException;
+import com.yahoo.ycsb.Client;
+import com.yahoo.ycsb.generator.IntegerGenerator;
+
+/**
+ * A disk-fragmenting workload.
+ * <p>
+ * Properties to control the client:
+ * </p>
+ * <UL>
+ * <LI><b>disksize</b>: how many bytes of storage can the disk store? (default 100,000,000)
+ * <LI><b>occupancy</b>: what fraction of the available storage should be used? (default 0.9)
+ * <LI><b>requestdistribution</b>: what distribution should be used to select the records to operate on - uniform, zipfian or latest (default: histogram)
+ * </ul> 
+ *
+ *
+ * <p> See also:
+ * Russell Sears, Catharine van Ingen.
+ * <a href='https://database.cs.wisc.edu/cidr/cidr2007/papers/cidr07p34.pdf'>Fragmentation in Large Object Repositories</a>,
+ * CIDR 2006. [<a href='https://database.cs.wisc.edu/cidr/cidr2007/slides/p34-sears.ppt'>Presentation</a>]
+ * </p>
+ *
+ *
+ * @author sears
+ *
+ */
+public class ConstantOccupancyWorkload extends CoreWorkload {
+	long disksize;
+	long storageages;
+	IntegerGenerator objectsizes;
+	double occupancy;
+	
+	long object_count;
+	
+	public static final String STORAGE_AGE_PROPERTY = "storageages";
+	public static final long   STORAGE_AGE_PROPERTY_DEFAULT = 10;
+	
+	public static final String DISK_SIZE_PROPERTY = "disksize";
+	public static final long   DISK_SIZE_PROPERTY_DEFAULT = 100 * 1000 * 1000;
+	
+	public static final String OCCUPANCY_PROPERTY = "occupancy";
+	public static final double OCCUPANCY_PROPERTY_DEFAULT = 0.9;
+	
+	@Override
+	public void init(Properties p) throws WorkloadException
+	{
+		disksize    = Long.parseLong(    p.getProperty(DISK_SIZE_PROPERTY, DISK_SIZE_PROPERTY_DEFAULT+""));
+		storageages = Long.parseLong(    p.getProperty(STORAGE_AGE_PROPERTY, STORAGE_AGE_PROPERTY_DEFAULT+""));
+		occupancy   = Double.parseDouble(p.getProperty(OCCUPANCY_PROPERTY, OCCUPANCY_PROPERTY_DEFAULT+""));
+		
+		if(p.getProperty(Client.RECORD_COUNT_PROPERTY) != null ||
+		   p.getProperty(Client.INSERT_COUNT_PROPERTY) != null ||
+		   p.getProperty(Client.OPERATION_COUNT_PROPERTY) != null) {
+			System.err.println("Warning: record, insert or operation count was set prior to initting ConstantOccupancyWorkload.  Overriding old values.");
+		}
+		IntegerGenerator g = CoreWorkload.getFieldLengthGenerator(p);
+		double fieldsize = g.mean();
+		int fieldcount = Integer.parseInt(p.getProperty(FIELD_COUNT_PROPERTY, FIELD_COUNT_PROPERTY_DEFAULT));
+
+		object_count = (long)(occupancy * ((double)disksize / (fieldsize * (double)fieldcount)));
+                if(object_count == 0) {
+                    throw new IllegalStateException("Object count was zero.  Perhaps disksize is too low?");
+                }
+		p.setProperty(Client.RECORD_COUNT_PROPERTY, object_count+"");
+		p.setProperty(Client.OPERATION_COUNT_PROPERTY, (storageages*object_count)+"");
+		p.setProperty(Client.INSERT_COUNT_PROPERTY, object_count+"");
+
+		super.init(p);
+	}
+
+}
diff --git a/src/com/yahoo/ycsb/workloads/CoreWorkload.java b/src/com/yahoo/ycsb/workloads/CoreWorkload.java
index dd1dbd064dc1442c197ecfb133f5964b823ab17c..2d17889396f870cda804249973d53f74b64c2415 100644
--- a/src/com/yahoo/ycsb/workloads/CoreWorkload.java
+++ b/src/com/yahoo/ycsb/workloads/CoreWorkload.java
@@ -21,8 +21,11 @@ import java.util.Properties;
 import com.yahoo.ycsb.*;
 import com.yahoo.ycsb.generator.CounterGenerator;
 import com.yahoo.ycsb.generator.DiscreteGenerator;
+import com.yahoo.ycsb.generator.ExponentialGenerator;
 import com.yahoo.ycsb.generator.Generator;
+import com.yahoo.ycsb.generator.ConstantIntegerGenerator;
 import com.yahoo.ycsb.generator.HotspotIntegerGenerator;
+import com.yahoo.ycsb.generator.HistogramGenerator;
 import com.yahoo.ycsb.generator.IntegerGenerator;
 import com.yahoo.ycsb.generator.ScrambledZipfianGenerator;
 import com.yahoo.ycsb.generator.SkewedLatestGenerator;
@@ -30,6 +33,7 @@ import com.yahoo.ycsb.generator.UniformIntegerGenerator;
 import com.yahoo.ycsb.generator.ZipfianGenerator;
 import com.yahoo.ycsb.measurements.Measurements;
 
+import java.io.IOException;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Vector;
@@ -84,18 +88,41 @@ public class CoreWorkload extends Workload
 
 	int fieldcount;
 
+	/**
+	 * The name of the property for the field length distribution. Options are "uniform", "zipfian" (favoring short records), "constant", and "histogram".
+	 * 
+	 * If "uniform", "zipfian" or "constant", the maximum field length will be that specified by the fieldlength property.  If "histogram", then the
+	 * histogram will be read from the filename specified in the "fieldlengthhistogram" property.
+	 */
+	public static final String FIELD_LENGTH_DISTRIBUTION_PROPERTY="fieldlengthdistribution";
+	/**
+	 * The default field length distribution.
+	 */
+	public static final String FIELD_LENGTH_DISTRIBUTION_PROPERTY_DEFAULT = "constant";
+
 	/**
 	 * The name of the property for the length of a field in bytes.
 	 */
 	public static final String FIELD_LENGTH_PROPERTY="fieldlength";
-	
 	/**
-	 * The default length of a field in bytes.
+	 * The default maximum length of a field in bytes.
 	 */
 	public static final String FIELD_LENGTH_PROPERTY_DEFAULT="100";
 
-	int fieldlength;
+	/**
+	 * The name of a property that specifies the filename containing the field length histogram (only used if fieldlengthdistribution is "histogram").
+	 */
+	public static final String FIELD_LENGTH_HISTOGRAM_FILE_PROPERTY = "fieldlengthhistogram";
+	/**
+	 * The default filename containing a field length histogram.
+	 */
+	public static final String FIELD_LENGTH_HISTOGRAM_FILE_PROPERTY_DEFAULT = "hist.txt";
 
+	/**
+	 * Generator object that produces field lengths.  The value of this depends on the properties that start with "FIELD_LENGTH_".
+	 */
+	IntegerGenerator fieldlengthgenerator;
+	
 	/**
 	 * The name of the property for deciding whether to read one field (false) or all fields (true) of a record.
 	 */
@@ -247,6 +274,29 @@ public class CoreWorkload extends Workload
 
 	int recordcount;
 	
+	protected static IntegerGenerator getFieldLengthGenerator(Properties p) throws WorkloadException{
+		IntegerGenerator fieldlengthgenerator;
+		String fieldlengthdistribution = p.getProperty(FIELD_LENGTH_DISTRIBUTION_PROPERTY, FIELD_LENGTH_DISTRIBUTION_PROPERTY_DEFAULT);
+		int fieldlength=Integer.parseInt(p.getProperty(FIELD_LENGTH_PROPERTY,FIELD_LENGTH_PROPERTY_DEFAULT));
+		String fieldlengthhistogram = p.getProperty(FIELD_LENGTH_HISTOGRAM_FILE_PROPERTY, FIELD_LENGTH_HISTOGRAM_FILE_PROPERTY_DEFAULT);
+		if(fieldlengthdistribution.compareTo("constant") == 0) {
+			fieldlengthgenerator = new ConstantIntegerGenerator(fieldlength);
+		} else if(fieldlengthdistribution.compareTo("uniform") == 0) {
+			fieldlengthgenerator = new UniformIntegerGenerator(1, fieldlength);
+		} else if(fieldlengthdistribution.compareTo("zipfian") == 0) {
+			fieldlengthgenerator = new ZipfianGenerator(1, fieldlength);
+		} else if(fieldlengthdistribution.compareTo("histogram") == 0) {
+			try {
+				fieldlengthgenerator = new HistogramGenerator(fieldlengthhistogram);
+			} catch(IOException e) {
+				throw new WorkloadException("Couldn't read field length histogram file: "+fieldlengthhistogram, e);
+			}
+		} else {
+			throw new WorkloadException("Unknown field length distribution \""+fieldlengthdistribution+"\"");
+		}
+		return fieldlengthgenerator;
+	}
+	
 	/**
 	 * Initialize the scenario. 
 	 * Called once, in the main client thread, before any operations are started.
@@ -254,8 +304,10 @@ public class CoreWorkload extends Workload
 	public void init(Properties p) throws WorkloadException
 	{
 		table = p.getProperty(TABLENAME_PROPERTY,TABLENAME_PROPERTY_DEFAULT);
+		
 		fieldcount=Integer.parseInt(p.getProperty(FIELD_COUNT_PROPERTY,FIELD_COUNT_PROPERTY_DEFAULT));
-		fieldlength=Integer.parseInt(p.getProperty(FIELD_LENGTH_PROPERTY,FIELD_LENGTH_PROPERTY_DEFAULT));
+		fieldlengthgenerator = CoreWorkload.getFieldLengthGenerator(p);
+		
 		double readproportion=Double.parseDouble(p.getProperty(READ_PROPORTION_PROPERTY,READ_PROPORTION_PROPERTY_DEFAULT));
 		double updateproportion=Double.parseDouble(p.getProperty(UPDATE_PROPORTION_PROPERTY,UPDATE_PROPORTION_PROPERTY_DEFAULT));
 		double insertproportion=Double.parseDouble(p.getProperty(INSERT_PROPORTION_PROPERTY,INSERT_PROPORTION_PROPERTY_DEFAULT));
@@ -275,6 +327,14 @@ public class CoreWorkload extends Workload
 		{
 			orderedinserts=false;
 		}
+		else if (requestdistrib.compareTo("exponential")==0)
+		{
+                    double percentile = Double.parseDouble(p.getProperty(ExponentialGenerator.EXPONENTIAL_PERCENTILE_PROPERTY,
+                                                                         ExponentialGenerator.EXPONENTIAL_PERCENTILE_DEFAULT));
+                    double frac       = Double.parseDouble(p.getProperty(ExponentialGenerator.EXPONENTIAL_FRAC_PROPERTY,
+                                                                         ExponentialGenerator.EXPONENTIAL_FRAC_DEFAULT));
+                    keychooser = new ExponentialGenerator(percentile, recordcount*frac);
+		}
 		else
 		{
 			orderedinserts=true;
@@ -341,7 +401,7 @@ public class CoreWorkload extends Workload
     }
 		else
 		{
-			throw new WorkloadException("Unknown distribution \""+requestdistrib+"\"");
+			throw new WorkloadException("Unknown request distribution \""+requestdistrib+"\"");
 		}
 
 		fieldchooser=new UniformIntegerGenerator(0,fieldcount-1);
@@ -360,6 +420,33 @@ public class CoreWorkload extends Workload
 		}
 	}
 
+	public String buildKeyName(long keynum) {
+ 		if (!orderedinserts)
+ 		{
+ 			keynum=Utils.hash(keynum);
+ 		}
+		return "user"+keynum;
+	}
+	HashMap<String, ByteIterator> buildValues() {
+ 		HashMap<String,ByteIterator> values=new HashMap<String,ByteIterator>();
+
+ 		for (int i=0; i<fieldcount; i++)
+ 		{
+ 			String fieldkey="field"+i;
+ 			ByteIterator data= new RandomByteIterator(fieldlengthgenerator.nextInt());
+ 			values.put(fieldkey,data);
+ 		}
+		return values;
+	}
+	HashMap<String, ByteIterator> buildUpdate() {
+		//update a random field
+		HashMap<String, ByteIterator> values=new HashMap<String,ByteIterator>();
+		String fieldname="field"+fieldchooser.nextString();
+		ByteIterator data = new RandomByteIterator(fieldlengthgenerator.nextInt());
+		values.put(fieldname,data);
+		return values;
+	}
+
 	/**
 	 * Do one insert operation. Because it will be called concurrently from multiple client threads, this 
 	 * function must be thread safe. However, avoid synchronized, or the threads will block waiting for each 
@@ -369,18 +456,8 @@ public class CoreWorkload extends Workload
 	public boolean doInsert(DB db, Object threadstate)
 	{
 		int keynum=keysequence.nextInt();
-		if (!orderedinserts)
-		{
-			keynum=Utils.hash(keynum);
-		}
-		String dbkey="user"+keynum;
-		HashMap<String,String> values=new HashMap<String,String>();
-		for (int i=0; i<fieldcount; i++)
-		{
-			String fieldkey="field"+i;
-			String data=Utils.ASCIIString(fieldlength);
-			values.put(fieldkey,data);
-		}
+		String dbkey = buildKeyName(keynum);
+		HashMap<String, ByteIterator> values = buildValues();
 		if (db.insert(table,dbkey,values) == 0)
 			return true;
 		else
@@ -421,22 +498,31 @@ public class CoreWorkload extends Workload
 		return true;
 	}
 
+    int nextKeynum() {
+        int keynum;
+        if(keychooser instanceof ExponentialGenerator) {
+            do
+                {
+                    keynum=transactioninsertkeysequence.lastInt() - keychooser.nextInt();
+                }
+            while(keynum < 0);
+        } else {
+            do
+                {
+                    keynum=keychooser.nextInt();
+                }
+            while (keynum > transactioninsertkeysequence.lastInt());
+        }
+        return keynum;
+    }
+
 	public void doTransactionRead(DB db)
 	{
 		//choose a random key
-		int keynum;
-		do
-		{
-			keynum=keychooser.nextInt();
-		}
-		while (keynum>transactioninsertkeysequence.lastInt());
+		int keynum = nextKeynum();
+		
+		String keyname = buildKeyName(keynum);
 		
-		if (!orderedinserts)
-		{
-			keynum=Utils.hash(keynum);
-		}
-		String keyname="user"+keynum;
-
 		HashSet<String> fields=null;
 
 		if (!readallfields)
@@ -448,24 +534,15 @@ public class CoreWorkload extends Workload
 			fields.add(fieldname);
 		}
 
-		db.read(table,keyname,fields,new HashMap<String,String>());
+		db.read(table,keyname,fields,new HashMap<String,ByteIterator>());
 	}
 	
 	public void doTransactionReadModifyWrite(DB db)
 	{
 		//choose a random key
-		int keynum;
-		do
-		{
-			keynum=keychooser.nextInt();
-		}
-		while (keynum>transactioninsertkeysequence.lastInt());
-		
-		if (!orderedinserts)
-		{
-			keynum=Utils.hash(keynum);
-		}
-		String keyname="user"+keynum;
+		int keynum = nextKeynum();
+
+		String keyname = buildKeyName(keynum);
 
 		HashSet<String> fields=null;
 
@@ -478,31 +555,24 @@ public class CoreWorkload extends Workload
 			fields.add(fieldname);
 		}
 		
-		HashMap<String,String> values=new HashMap<String,String>();
+		HashMap<String,ByteIterator> values;
 
 		if (writeallfields)
 		{
 		   //new data for all the fields
-		   for (int i=0; i<fieldcount; i++)
-		   {
-		      String fieldname="field"+i;
-		      String data=Utils.ASCIIString(fieldlength);		   
-		      values.put(fieldname,data);
-		   }
+		   values = buildValues();
 		}
 		else
 		{
 		   //update a random field
-		   String fieldname="field"+fieldchooser.nextString();
-		   String data=Utils.ASCIIString(fieldlength);		   
-		   values.put(fieldname,data);
+		   values = buildUpdate();
 		}
 
 		//do the transaction
 		
 		long st=System.currentTimeMillis();
 
-		db.read(table,keyname,fields,new HashMap<String,String>());
+		db.read(table,keyname,fields,new HashMap<String,ByteIterator>());
 		
 		db.update(table,keyname,values);
 
@@ -514,18 +584,9 @@ public class CoreWorkload extends Workload
 	public void doTransactionScan(DB db)
 	{
 		//choose a random key
-		int keynum;
-		do
-		{
-			keynum=keychooser.nextInt();
-		}
-		while (keynum>transactioninsertkeysequence.lastInt());
+		int keynum = nextKeynum();
 
-		if (!orderedinserts)
-		{
-			keynum=Utils.hash(keynum);
-		}
-		String startkeyname="user"+keynum;
+		String startkeyname = buildKeyName(keynum);
 		
 		//choose a random scan length
 		int len=scanlength.nextInt();
@@ -541,43 +602,27 @@ public class CoreWorkload extends Workload
 			fields.add(fieldname);
 		}
 
-		db.scan(table,startkeyname,len,fields,new Vector<HashMap<String,String>>());
+		db.scan(table,startkeyname,len,fields,new Vector<HashMap<String,ByteIterator>>());
 	}
 
 	public void doTransactionUpdate(DB db)
 	{
 		//choose a random key
-		int keynum;
-		do
-		{
-			keynum=keychooser.nextInt();
-		}
-		while (keynum>transactioninsertkeysequence.lastInt());
+		int keynum = nextKeynum();
 
-		if (!orderedinserts)
-		{
-			keynum=Utils.hash(keynum);
-		}
-		String keyname="user"+keynum;
+		String keyname=buildKeyName(keynum);
 
-		HashMap<String,String> values=new HashMap<String,String>();
+		HashMap<String,ByteIterator> values;
 
 		if (writeallfields)
 		{
 		   //new data for all the fields
-		   for (int i=0; i<fieldcount; i++)
-		   {
-		      String fieldname="field"+i;
-		      String data=Utils.ASCIIString(fieldlength);		   
-		      values.put(fieldname,data);
-		   }
+		   values = buildValues();
 		}
 		else
 		{
 		   //update a random field
-		   String fieldname="field"+fieldchooser.nextString();
-		   String data=Utils.ASCIIString(fieldlength);		   
-		   values.put(fieldname,data);
+		   values = buildUpdate();
 		}
 
 		db.update(table,keyname,values);
@@ -587,19 +632,10 @@ public class CoreWorkload extends Workload
 	{
 		//choose the next key
 		int keynum=transactioninsertkeysequence.nextInt();
-		if (!orderedinserts)
-		{
-			keynum=Utils.hash(keynum);
-		}
-		String dbkey="user"+keynum;
-		
-		HashMap<String,String> values=new HashMap<String,String>();
-		for (int i=0; i<fieldcount; i++)
-		{
-			String fieldkey="field"+i;
-			String data=Utils.ASCIIString(fieldlength);
-			values.put(fieldkey,data);
-		}
+
+		String dbkey = buildKeyName(keynum);
+
+		HashMap<String, ByteIterator> values = buildValues();
 		db.insert(table,dbkey,values);
 	}
 }