Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Mavenisation of the YCSB with a (tar ball) distribution packager.

  • Loading branch information...
commit 3532283de4d1f2baae6502e7c58dfbcbb8924a24 1 parent 424a25e
Hariprasad Kuppuswamy authored
Showing with 9,994 additions and 0 deletions.
  1. +51 −0 cassandra/pom.xml
  2. +619 −0 cassandra/src/main/java/com/yahoo/ycsb/db/CassandraClient10.java
  3. +31 −0 core/pom.xml
  4. +267 −0 core/src/main/java/com/yahoo/ycsb/BasicDB.java
  5. +52 −0 core/src/main/java/com/yahoo/ycsb/ByteArrayByteIterator.java
  6. +92 −0 core/src/main/java/com/yahoo/ycsb/ByteIterator.java
  7. +802 −0 core/src/main/java/com/yahoo/ycsb/Client.java
  8. +410 −0 core/src/main/java/com/yahoo/ycsb/CommandLine.java
  9. +137 −0 core/src/main/java/com/yahoo/ycsb/DB.java
  10. +50 −0 core/src/main/java/com/yahoo/ycsb/DBException.java
  11. +52 −0 core/src/main/java/com/yahoo/ycsb/DBFactory.java
  12. +168 −0 core/src/main/java/com/yahoo/ycsb/DBWrapper.java
  13. +55 −0 core/src/main/java/com/yahoo/ycsb/InputStreamByteIterator.java
  14. +84 −0 core/src/main/java/com/yahoo/ycsb/RandomByteIterator.java
  15. +108 −0 core/src/main/java/com/yahoo/ycsb/StringByteIterator.java
  16. +70 −0 core/src/main/java/com/yahoo/ycsb/TerminatorThread.java
  17. +50 −0 core/src/main/java/com/yahoo/ycsb/UnknownDBException.java
  18. +116 −0 core/src/main/java/com/yahoo/ycsb/Utils.java
  19. +112 −0 core/src/main/java/com/yahoo/ycsb/Workload.java
  20. +50 −0 core/src/main/java/com/yahoo/ycsb/WorkloadException.java
  21. +44 −0 core/src/main/java/com/yahoo/ycsb/generator/ConstantIntegerGenerator.java
  22. +57 −0 core/src/main/java/com/yahoo/ycsb/generator/CounterGenerator.java
  23. +114 −0 core/src/main/java/com/yahoo/ycsb/generator/DiscreteGenerator.java
  24. +102 −0 core/src/main/java/com/yahoo/ycsb/generator/ExponentialGenerator.java
  25. +88 −0 core/src/main/java/com/yahoo/ycsb/generator/FileGenerator.java
  26. +37 −0 core/src/main/java/com/yahoo/ycsb/generator/Generator.java
  27. +114 −0 core/src/main/java/com/yahoo/ycsb/generator/HistogramGenerator.java
  28. +124 −0 core/src/main/java/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java
  29. +75 −0 core/src/main/java/com/yahoo/ycsb/generator/IntegerGenerator.java
  30. +137 −0 core/src/main/java/com/yahoo/ycsb/generator/ScrambledZipfianGenerator.java
  31. +61 −0 core/src/main/java/com/yahoo/ycsb/generator/SkewedLatestGenerator.java
  32. +67 −0 core/src/main/java/com/yahoo/ycsb/generator/UniformGenerator.java
  33. +57 −0 core/src/main/java/com/yahoo/ycsb/generator/UniformIntegerGenerator.java
  34. +325 −0 core/src/main/java/com/yahoo/ycsb/generator/ZipfianGenerator.java
  35. +167 −0 core/src/main/java/com/yahoo/ycsb/measurements/Measurements.java
  36. +55 −0 core/src/main/java/com/yahoo/ycsb/measurements/OneMeasurement.java
  37. +165 −0 core/src/main/java/com/yahoo/ycsb/measurements/OneMeasurementHistogram.java
  38. +179 −0 core/src/main/java/com/yahoo/ycsb/measurements/OneMeasurementTimeSeries.java
  39. +71 −0 core/src/main/java/com/yahoo/ycsb/measurements/exporter/JSONMeasurementsExporter.java
  40. +49 −0 core/src/main/java/com/yahoo/ycsb/measurements/exporter/MeasurementsExporter.java
  41. +54 −0 core/src/main/java/com/yahoo/ycsb/measurements/exporter/TextMeasurementsExporter.java
  42. +91 −0 core/src/main/java/com/yahoo/ycsb/workloads/ConstantOccupancyWorkload.java
  43. +641 −0 core/src/main/java/com/yahoo/ycsb/workloads/CoreWorkload.java
  44. BIN  distribution/lib/hbase-binding-0.1.3.jar
  45. +99 −0 distribution/pom.xml
  46. +42 −0 distribution/src/main/assembly/distribution.xml
  47. +125 −0 distribution/src/main/bin/ycsb.sh
  48. +37 −0 distribution/src/main/resources/workloads/workloada
  49. +36 −0 distribution/src/main/resources/workloads/workloadb
  50. +38 −0 distribution/src/main/resources/workloads/workloadc
  51. +41 −0 distribution/src/main/resources/workloads/workloadd
  52. +46 −0 distribution/src/main/resources/workloads/workloade
  53. +37 −0 distribution/src/main/resources/workloads/workloadf
  54. +63 −0 gemfire/pom.xml
  55. +9 −0 gemfire/src/main/conf/cache.xml
  56. +200 −0 gemfire/src/main/java/com/yahoo/ycsb/db/GemFireClient.java
  57. +50 −0 hbase/pom.xml
  58. +41 −0 hbase/src/main/conf/hbase-site.xml
  59. +520 −0 hbase/src/main/java/com/yahoo/ycsb/db/HBaseClient.java
  60. +51 −0 infinispan/pom.xml
  61. +17 −0 infinispan/src/main/conf/infinispan-config.xml
  62. +136 −0 infinispan/src/main/java/com/yahoo/ycsb/db/InfinispanClient.java
  63. +51 −0 jdbc/pom.xml
  64. +6 −0 jdbc/src/main/conf/db.properties
  65. +6 −0 jdbc/src/main/conf/h2.properties
  66. +178 −0 jdbc/src/main/java/com/yahoo/ycsb/db/JdbcDBCli.java
  67. +449 −0 jdbc/src/main/java/com/yahoo/ycsb/db/JdbcDBClient.java
  68. +56 −0 jdbc/src/main/java/com/yahoo/ycsb/db/JdbcDBClientConstants.java
  69. +220 −0 jdbc/src/main/java/com/yahoo/ycsb/db/JdbcDBCreateTable.java
  70. +1 −0  jdbc/src/main/resources/sql/README
  71. +12 −0 jdbc/src/main/resources/sql/create_table.mysql
  72. +12 −0 jdbc/src/main/resources/sql/create_table.sql
  73. +51 −0 mapkeeper/pom.xml
  74. +196 −0 mapkeeper/src/main/java/com/yahoo/ycsb/db/MapKeeperClient.java
  75. +51 −0 mongodb/pom.xml
  76. +318 −0 mongodb/src/main/java/com/yahoo/ycsb/db/MongoDbClient.java
  77. +44 −0 pom.xml
  78. +52 −0 redis/pom.xml
  79. +131 −0 redis/src/main/java/com/yahoo/ycsb/db/RedisClient.java
  80. +65 −0 voldemort/pom.xml
  81. +11 −0 voldemort/src/main/conf/cluster.xml
  82. +26 −0 voldemort/src/main/conf/server.properties
  83. +16 −0 voldemort/src/main/conf/stores.xml
  84. +151 −0 voldemort/src/main/java/com/yahoo/ycsb/db/VoldemortClient.java
  85. +11 −0 voldemort/src/main/resources/config/cluster.xml
  86. +26 −0 voldemort/src/main/resources/config/server.properties
  87. +16 −0 voldemort/src/main/resources/config/stores.xml
View
51 cassandra/pom.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.ycsb</groupId>
+ <artifactId>root</artifactId>
+ <version>0.1.3</version>
+ </parent>
+
+ <artifactId>cassandra-binding</artifactId>
+ <name>Cassandra DB Binding</name>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.cassandra</groupId>
+ <artifactId>cassandra-all</artifactId>
+ <version>${cassandra.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ycsb</groupId>
+ <artifactId>core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>${maven.assembly.version}</version>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ <appendAssemblyId>false</appendAssemblyId>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
View
619 cassandra/src/main/java/com/yahoo/ycsb/db/CassandraClient10.java
@@ -0,0 +1,619 @@
+/**
+ * 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.db;
+
+import com.yahoo.ycsb.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Vector;
+import java.util.Random;
+import java.util.Properties;
+import java.nio.ByteBuffer;
+
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TFramedTransport;
+import org.apache.thrift.transport.TSocket;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.cassandra.thrift.*;
+
+
+//XXXX if we do replication, fix the consistency levels
+/**
+ * Cassandra 1.0.6 client for YCSB framework
+ */
+public class CassandraClient10 extends DB
+{
+ static Random random = new Random();
+ public static final int Ok = 0;
+ public static final int Error = -1;
+ public static final ByteBuffer emptyByteBuffer = ByteBuffer.wrap(new byte[0]);
+
+ public int ConnectionRetries;
+ public int OperationRetries;
+ public String column_family;
+
+ public static final String CONNECTION_RETRY_PROPERTY = "cassandra.connectionretries";
+ public static final String CONNECTION_RETRY_PROPERTY_DEFAULT = "300";
+
+ public static final String OPERATION_RETRY_PROPERTY = "cassandra.operationretries";
+ public static final String OPERATION_RETRY_PROPERTY_DEFAULT = "300";
+
+ public static final String USERNAME_PROPERTY = "cassandra.username";
+ public static final String PASSWORD_PROPERTY = "cassandra.password";
+
+ public static final String COLUMN_FAMILY_PROPERTY = "cassandra.columnfamily";
+ public static final String COLUMN_FAMILY_PROPERTY_DEFAULT = "data";
+
+ TTransport tr;
+ Cassandra.Client client;
+
+ boolean _debug = false;
+
+ String _table = "";
+ Exception errorexception = null;
+
+ List<Mutation> mutations = new ArrayList<Mutation>();
+ Map<String, List<Mutation>> mutationMap = new HashMap<String, List<Mutation>>();
+ Map<ByteBuffer, Map<String, List<Mutation>>> record = new HashMap<ByteBuffer, Map<String, List<Mutation>>>();
+
+ ColumnParent parent;
+
+ /**
+ * Initialize any state for this DB. Called once per DB instance; there is one
+ * DB instance per client thread.
+ */
+ public void init() throws DBException
+ {
+ String hosts = getProperties().getProperty("hosts");
+ if (hosts == null)
+ {
+ throw new DBException("Required property \"hosts\" missing for CassandraClient");
+ }
+
+ column_family = getProperties().getProperty(COLUMN_FAMILY_PROPERTY, COLUMN_FAMILY_PROPERTY_DEFAULT);
+ parent = new ColumnParent(column_family);
+
+ ConnectionRetries = Integer.parseInt(getProperties().getProperty(CONNECTION_RETRY_PROPERTY,
+ CONNECTION_RETRY_PROPERTY_DEFAULT));
+ OperationRetries = Integer.parseInt(getProperties().getProperty(OPERATION_RETRY_PROPERTY,
+ OPERATION_RETRY_PROPERTY_DEFAULT));
+
+ String username = getProperties().getProperty(USERNAME_PROPERTY);
+ String password = getProperties().getProperty(PASSWORD_PROPERTY);
+
+ _debug = Boolean.parseBoolean(getProperties().getProperty("debug", "false"));
+
+ String[] allhosts = hosts.split(",");
+ String myhost = allhosts[random.nextInt(allhosts.length)];
+
+ Exception connectexception = null;
+
+ for (int retry = 0; retry < ConnectionRetries; retry++)
+ {
+ tr = new TFramedTransport(new TSocket(myhost, 9160));
+ TProtocol proto = new TBinaryProtocol(tr);
+ client = new Cassandra.Client(proto);
+ try
+ {
+ tr.open();
+ connectexception = null;
+ break;
+ } catch (Exception e)
+ {
+ connectexception = e;
+ }
+ try
+ {
+ Thread.sleep(1000);
+ } catch (InterruptedException e)
+ {
+ }
+ }
+ if (connectexception != null)
+ {
+ System.err.println("Unable to connect to " + myhost + " after " + ConnectionRetries
+ + " tries");
+ System.out.println("Unable to connect to " + myhost + " after " + ConnectionRetries
+ + " tries");
+ throw new DBException(connectexception);
+ }
+
+ if (username != null && password != null)
+ {
+ Map<String,String> cred = new HashMap<String,String>();
+ cred.put("username", username);
+ cred.put("password", password);
+ AuthenticationRequest req = new AuthenticationRequest(cred);
+ try
+ {
+ client.login(req);
+ }
+ catch (Exception e)
+ {
+ throw new DBException(e);
+ }
+ }
+ }
+
+ /**
+ * Cleanup any state for this DB. Called once per DB instance; there is one DB
+ * instance per client thread.
+ */
+ public void cleanup() throws DBException
+ {
+ tr.close();
+ }
+
+ /**
+ * Read a record from the database. Each field/value pair from the result will
+ * be stored in a HashMap.
+ *
+ * @param table
+ * The name of the table
+ * @param key
+ * The record key of the record to read.
+ * @param fields
+ * The list of fields to read, or null for all of them
+ * @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, ByteIterator> result)
+ {
+ if (!_table.equals(table)) {
+ try
+ {
+ client.set_keyspace(table);
+ _table = table;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ e.printStackTrace(System.out);
+ return Error;
+ }
+ }
+
+ for (int i = 0; i < OperationRetries; i++)
+ {
+
+ try
+ {
+ SlicePredicate predicate;
+ if (fields == null)
+ {
+ predicate = new SlicePredicate().setSlice_range(new SliceRange(emptyByteBuffer, emptyByteBuffer, false, 1000000));
+
+ } else {
+ ArrayList<ByteBuffer> fieldlist = new ArrayList<ByteBuffer>(fields.size());
+ for (String s : fields)
+ {
+ fieldlist.add(ByteBuffer.wrap(s.getBytes("UTF-8")));
+ }
+
+ predicate = new SlicePredicate().setColumn_names(fieldlist);
+ }
+
+ List<ColumnOrSuperColumn> results = client.get_slice(ByteBuffer.wrap(key.getBytes("UTF-8")), parent, predicate, ConsistencyLevel.ONE);
+
+ if (_debug)
+ {
+ System.out.print("Reading key: " + key);
+ }
+
+ Column column;
+ String name;
+ 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 ByteArrayByteIterator(column.value.array(), column.value.position()+column.value.arrayOffset(), column.value.remaining());
+
+ result.put(name,value);
+
+ if (_debug)
+ {
+ System.out.print("(" + name + "=" + value + ")");
+ }
+ }
+
+ if (_debug)
+ {
+ System.out.println();
+ }
+
+ return Ok;
+ } catch (Exception e)
+ {
+ errorexception = e;
+ }
+
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
+ {
+ }
+ }
+ errorexception.printStackTrace();
+ errorexception.printStackTrace(System.out);
+ return Error;
+
+ }
+
+ /**
+ * 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.
+ *
+ * @param table
+ * The name of the table
+ * @param startkey
+ * The record key of the first record to read.
+ * @param recordcount
+ * The number of records to read
+ * @param fields
+ * The list of fields to read, or null for all of them
+ * @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, ByteIterator>> result)
+ {
+ if (!_table.equals(table)) {
+ try
+ {
+ client.set_keyspace(table);
+ _table = table;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ e.printStackTrace(System.out);
+ return Error;
+ }
+ }
+
+ for (int i = 0; i < OperationRetries; i++)
+ {
+
+ try
+ {
+ SlicePredicate predicate;
+ if (fields == null)
+ {
+ predicate = new SlicePredicate().setSlice_range(new SliceRange(emptyByteBuffer, emptyByteBuffer, false, 1000000));
+
+ } else {
+ ArrayList<ByteBuffer> fieldlist = new ArrayList<ByteBuffer>(fields.size());
+ for (String s : fields)
+ {
+ fieldlist.add(ByteBuffer.wrap(s.getBytes("UTF-8")));
+ }
+
+ predicate = new SlicePredicate().setColumn_names(fieldlist);
+ }
+
+ KeyRange kr = new KeyRange().setStart_key(startkey.getBytes("UTF-8")).setEnd_key(new byte[] {}).setCount(recordcount);
+
+ List<KeySlice> results = client.get_range_slices(parent, predicate, kr, ConsistencyLevel.ONE);
+
+ if (_debug)
+ {
+ System.out.println("Scanning startkey: " + startkey);
+ }
+
+ HashMap<String, ByteIterator> tuple;
+ for (KeySlice oneresult : results)
+ {
+ tuple = new HashMap<String, ByteIterator>();
+
+ Column column;
+ String name;
+ 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 ByteArrayByteIterator(column.value.array(), column.value.position()+column.value.arrayOffset(), column.value.remaining());
+
+ tuple.put(name, value);
+
+ if (_debug)
+ {
+ System.out.print("(" + name + "=" + value + ")");
+ }
+ }
+
+ result.add(tuple);
+ if (_debug)
+ {
+ System.out.println();
+ }
+ }
+
+ return Ok;
+ } catch (Exception e)
+ {
+ errorexception = e;
+ }
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
+ {
+ }
+ }
+ errorexception.printStackTrace();
+ errorexception.printStackTrace(System.out);
+ return Error;
+ }
+
+ /**
+ * Update a record in the database. Any field/value pairs in the specified
+ * values HashMap will be written into the record with the specified record
+ * key, overwriting any existing values with the same field name.
+ *
+ * @param table
+ * The name of the table
+ * @param key
+ * The record key of the record to write.
+ * @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, ByteIterator> values)
+ {
+ return insert(table, key, 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 record
+ * key.
+ *
+ * @param table
+ * The name of the table
+ * @param key
+ * The record key of the record to insert.
+ * @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, ByteIterator> values)
+ {
+ if (!_table.equals(table)) {
+ try
+ {
+ client.set_keyspace(table);
+ _table = table;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ e.printStackTrace(System.out);
+ return Error;
+ }
+ }
+
+ for (int i = 0; i < OperationRetries; i++)
+ {
+ if (_debug)
+ {
+ System.out.println("Inserting key: " + key);
+ }
+
+ try
+ {
+ ByteBuffer wrappedKey = ByteBuffer.wrap(key.getBytes("UTF-8"));
+
+ Column col;
+ ColumnOrSuperColumn column;
+ 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().toArray()));
+ col.setTimestamp(System.currentTimeMillis());
+
+ column = new ColumnOrSuperColumn();
+ column.setColumn(col);
+
+ mutations.add(new Mutation().setColumn_or_supercolumn(column));
+ }
+
+ mutationMap.put(column_family, mutations);
+ record.put(wrappedKey, mutationMap);
+
+ client.batch_mutate(record, ConsistencyLevel.ONE);
+
+ mutations.clear();
+ mutationMap.clear();
+ record.clear();
+
+ return Ok;
+ } catch (Exception e)
+ {
+ errorexception = e;
+ }
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
+ {
+ }
+ }
+
+ errorexception.printStackTrace();
+ errorexception.printStackTrace(System.out);
+ return Error;
+ }
+
+ /**
+ * Delete a record from the database.
+ *
+ * @param table
+ * The name of the table
+ * @param key
+ * The record key of the record to delete.
+ * @return Zero on success, a non-zero error code on error
+ */
+ public int delete(String table, String key)
+ {
+ if (!_table.equals(table)) {
+ try
+ {
+ client.set_keyspace(table);
+ _table = table;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ e.printStackTrace(System.out);
+ return Error;
+ }
+ }
+
+ for (int i = 0; i < OperationRetries; i++)
+ {
+ try
+ {
+ client.remove(ByteBuffer.wrap(key.getBytes("UTF-8")),
+ new ColumnPath(column_family),
+ System.currentTimeMillis(),
+ ConsistencyLevel.ONE);
+
+ if (_debug)
+ {
+ System.out.println("Delete key: " + key);
+ }
+
+ return Ok;
+ } catch (Exception e)
+ {
+ errorexception = e;
+ }
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
+ {
+ }
+ }
+ errorexception.printStackTrace();
+ errorexception.printStackTrace(System.out);
+ return Error;
+ }
+
+ public static void main(String[] args)
+ {
+ CassandraClient10 cli = new CassandraClient10();
+
+ Properties props = new Properties();
+
+ props.setProperty("hosts", args[0]);
+ cli.setProperties(props);
+
+ try
+ {
+ cli.init();
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ System.exit(0);
+ }
+
+ 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, ByteIterator> result = new HashMap<String, ByteIterator>();
+ HashSet<String> fields = new HashSet<String>();
+ fields.add("middlename");
+ fields.add("age");
+ fields.add("favoritecolor");
+ res = cli.read("usertable", "BrianFrankCooper", null, result);
+ System.out.println("Result of read: " + res);
+ for (String s : result.keySet())
+ {
+ System.out.println("[" + s + "]=[" + result.get(s) + "]");
+ }
+
+ res = cli.delete("usertable", "BrianFrankCooper");
+ System.out.println("Result of delete: " + res);
+ }
+
+ /*
+ * public static void main(String[] args) throws TException,
+ * InvalidRequestException, UnavailableException,
+ * UnsupportedEncodingException, NotFoundException {
+ *
+ *
+ *
+ * String key_user_id = "1";
+ *
+ *
+ *
+ *
+ * client.insert("Keyspace1", key_user_id, new ColumnPath("Standard1", null,
+ * "age".getBytes("UTF-8")), "24".getBytes("UTF-8"), timestamp,
+ * ConsistencyLevel.ONE);
+ *
+ *
+ * // read single column ColumnPath path = new ColumnPath("Standard1", null,
+ * "name".getBytes("UTF-8"));
+ *
+ * System.out.println(client.get("Keyspace1", key_user_id, path,
+ * ConsistencyLevel.ONE));
+ *
+ *
+ * // read entire row SlicePredicate predicate = new SlicePredicate(null, new
+ * SliceRange(new byte[0], new byte[0], false, 10));
+ *
+ * ColumnParent parent = new ColumnParent("Standard1", null);
+ *
+ * List<ColumnOrSuperColumn> results = client.get_slice("Keyspace1",
+ * key_user_id, parent, predicate, ConsistencyLevel.ONE);
+ *
+ * for (ColumnOrSuperColumn result : results) {
+ *
+ * Column column = result.column;
+ *
+ * System.out.println(new String(column.name, "UTF-8") + " -> " + new
+ * String(column.value, "UTF-8"));
+ *
+ * }
+ *
+ *
+ *
+ *
+ * }
+ */
+}
View
31 core/pom.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.ycsb</groupId>
+ <artifactId>root</artifactId>
+ <version>0.1.3</version>
+ </parent>
+
+ <artifactId>core</artifactId>
+ <name>Core YCSB</name>
+ <packaging>jar</packaging>
+
+ <properties>
+ <jackson.api.version>1.9.4</jackson.api.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ <version>${jackson.api.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ <version>${jackson.api.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
View
267 core/src/main/java/com/yahoo/ycsb/BasicDB.java
@@ -0,0 +1,267 @@
+/**
+ * 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.HashMap;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Enumeration;
+import java.util.Vector;
+
+
+/**
+ * Basic DB that just prints out the requested operations, instead of doing them against a database.
+ */
+public class BasicDB extends DB
+{
+ public static final String VERBOSE="basicdb.verbose";
+ public static final String VERBOSE_DEFAULT="true";
+
+ public static final String SIMULATE_DELAY="basicdb.simulatedelay";
+ public static final String SIMULATE_DELAY_DEFAULT="0";
+
+
+ boolean verbose;
+ int todelay;
+
+ public BasicDB()
+ {
+ todelay=0;
+ }
+
+
+ void delay()
+ {
+ if (todelay>0)
+ {
+ try
+ {
+ Thread.sleep((long)Utils.random().nextInt(todelay));
+ }
+ catch (InterruptedException e)
+ {
+ //do nothing
+ }
+ }
+ }
+
+ /**
+ * Initialize any state for this DB.
+ * Called once per DB instance; there is one DB instance per client thread.
+ */
+ @SuppressWarnings("unchecked")
+ public void init()
+ {
+ verbose=Boolean.parseBoolean(getProperties().getProperty(VERBOSE, VERBOSE_DEFAULT));
+ todelay=Integer.parseInt(getProperties().getProperty(SIMULATE_DELAY, SIMULATE_DELAY_DEFAULT));
+
+ if (verbose)
+ {
+ System.out.println("***************** properties *****************");
+ Properties p=getProperties();
+ if (p!=null)
+ {
+ for (Enumeration e=p.propertyNames(); e.hasMoreElements(); )
+ {
+ String k=(String)e.nextElement();
+ System.out.println("\""+k+"\"=\""+p.getProperty(k)+"\"");
+ }
+ }
+ System.out.println("**********************************************");
+ }
+ }
+
+ /**
+ * Read a record from the database. Each field/value pair from the result will be stored in a HashMap.
+ *
+ * @param table The name of the table
+ * @param key The record key of the record to read.
+ * @param fields The list of fields to read, or null for all of them
+ * @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,ByteIterator> result)
+ {
+ delay();
+
+ if (verbose)
+ {
+ System.out.print("READ "+table+" "+key+" [ ");
+ if (fields!=null)
+ {
+ for (String f : fields)
+ {
+ System.out.print(f+" ");
+ }
+ }
+ else
+ {
+ System.out.print("<all fields>");
+ }
+
+ System.out.println("]");
+ }
+
+ return 0;
+ }
+
+ /**
+ * 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.
+ *
+ * @param table The name of the table
+ * @param startkey The record key of the first record to read.
+ * @param recordcount The number of records to read
+ * @param fields The list of fields to read, or null for all of them
+ * @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,ByteIterator>> result)
+ {
+ delay();
+
+ if (verbose)
+ {
+ System.out.print("SCAN "+table+" "+startkey+" "+recordcount+" [ ");
+ if (fields!=null)
+ {
+ for (String f : fields)
+ {
+ System.out.print(f+" ");
+ }
+ }
+ else
+ {
+ System.out.print("<all fields>");
+ }
+
+ System.out.println("]");
+ }
+
+ return 0;
+ }
+
+ /**
+ * Update a record in the database. Any field/value pairs in the specified values HashMap will be written into the record with the specified
+ * record key, overwriting any existing values with the same field name.
+ *
+ * @param table The name of the table
+ * @param key The record key of the record to write.
+ * @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,ByteIterator> values)
+ {
+ delay();
+
+ if (verbose)
+ {
+ System.out.print("UPDATE "+table+" "+key+" [ ");
+ if (values!=null)
+ {
+ for (String k : values.keySet())
+ {
+ System.out.print(k+"="+values.get(k)+" ");
+ }
+ }
+ System.out.println("]");
+ }
+
+ return 0;
+ }
+
+ /**
+ * Insert a record in the database. Any field/value pairs in the specified values HashMap will be written into the record with the specified
+ * record key.
+ *
+ * @param table The name of the table
+ * @param key The record key of the record to insert.
+ * @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,ByteIterator> values)
+ {
+ delay();
+
+ if (verbose)
+ {
+ System.out.print("INSERT "+table+" "+key+" [ ");
+ if (values!=null)
+ {
+ for (String k : values.keySet())
+ {
+ System.out.print(k+"="+values.get(k)+" ");
+ }
+ }
+
+ System.out.println("]");
+ }
+
+ return 0;
+ }
+
+
+ /**
+ * Delete a record from the database.
+ *
+ * @param table The name of the table
+ * @param key The record key of the record to delete.
+ * @return Zero on success, a non-zero error code on error
+ */
+ public int delete(String table, String key)
+ {
+ delay();
+
+ if (verbose)
+ {
+ System.out.println("DELETE "+table+" "+key);
+ }
+
+ return 0;
+ }
+
+ /**
+ * Short test of BasicDB
+ */
+ /*
+ public static void main(String[] args)
+ {
+ BasicDB bdb=new BasicDB();
+
+ Properties p=new Properties();
+ p.setProperty("Sky","Blue");
+ p.setProperty("Ocean","Wet");
+
+ bdb.setProperties(p);
+
+ bdb.init();
+
+ HashMap<String,String> fields=new HashMap<String,String>();
+ fields.put("A","X");
+ fields.put("B","Y");
+
+ bdb.read("table","key",null,null);
+ bdb.insert("table","key",fields);
+
+ fields=new HashMap<String,String>();
+ fields.put("C","Z");
+
+ bdb.update("table","key",fields);
+
+ bdb.delete("table","key");
+ }*/
+}
View
52 core/src/main/java/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;
+ }
+
+}
View
92 core/src/main/java/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;
+ }
+
+}
View
802 core/src/main/java/com/yahoo/ycsb/Client.java
@@ -0,0 +1,802 @@
+/**
+ * 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.*;
+import java.text.DecimalFormat;
+import java.util.*;
+
+import com.yahoo.ycsb.measurements.Measurements;
+import com.yahoo.ycsb.measurements.exporter.MeasurementsExporter;
+import com.yahoo.ycsb.measurements.exporter.TextMeasurementsExporter;
+
+//import org.apache.log4j.BasicConfigurator;
+
+/**
+ * A thread to periodically show the status of the experiment, to reassure you that progress is being made.
+ *
+ * @author cooperb
+ *
+ */
+class StatusThread extends Thread
+{
+ Vector<Thread> _threads;
+ String _label;
+ boolean _standardstatus;
+
+ /**
+ * The interval for reporting status.
+ */
+ public static final long sleeptime=10000;
+
+ public StatusThread(Vector<Thread> threads, String label, boolean standardstatus)
+ {
+ _threads=threads;
+ _label=label;
+ _standardstatus=standardstatus;
+ }
+
+ /**
+ * Run and periodically report status.
+ */
+ public void run()
+ {
+ long st=System.currentTimeMillis();
+
+ long lasten=st;
+ long lasttotalops=0;
+
+ boolean alldone;
+
+ do
+ {
+ alldone=true;
+
+ int totalops=0;
+
+ //terminate this thread when all the worker threads are done
+ for (Thread t : _threads)
+ {
+ if (t.getState()!=Thread.State.TERMINATED)
+ {
+ alldone=false;
+ }
+
+ ClientThread ct=(ClientThread)t;
+ totalops+=ct.getOpsDone();
+ }
+
+ long en=System.currentTimeMillis();
+
+ long interval=en-st;
+ //double throughput=1000.0*((double)totalops)/((double)interval);
+
+ double curthroughput=1000.0*(((double)(totalops-lasttotalops))/((double)(en-lasten)));
+
+ lasttotalops=totalops;
+ lasten=en;
+
+ DecimalFormat d = new DecimalFormat("#.##");
+
+ if (totalops==0)
+ {
+ System.err.println(_label+" "+(interval/1000)+" sec: "+totalops+" operations; "+Measurements.getMeasurements().getSummary());
+ }
+ else
+ {
+ System.err.println(_label+" "+(interval/1000)+" sec: "+totalops+" operations; "+d.format(curthroughput)+" current ops/sec; "+Measurements.getMeasurements().getSummary());
+ }
+
+ if (_standardstatus)
+ {
+ if (totalops==0)
+ {
+ System.out.println(_label+" "+(interval/1000)+" sec: "+totalops+" operations; "+Measurements.getMeasurements().getSummary());
+ }
+ else
+ {
+ System.out.println(_label+" "+(interval/1000)+" sec: "+totalops+" operations; "+d.format(curthroughput)+" current ops/sec; "+Measurements.getMeasurements().getSummary());
+ }
+ }
+
+ try
+ {
+ sleep(sleeptime);
+ }
+ catch (InterruptedException e)
+ {
+ //do nothing
+ }
+
+ }
+ while (!alldone);
+ }
+}
+
+/**
+ * A thread for executing transactions or data inserts to the database.
+ *
+ * @author cooperb
+ *
+ */
+class ClientThread extends Thread
+{
+ DB _db;
+ boolean _dotransactions;
+ Workload _workload;
+ int _opcount;
+ double _target;
+
+ int _opsdone;
+ int _threadid;
+ int _threadcount;
+ Object _workloadstate;
+ Properties _props;
+
+
+ /**
+ * Constructor.
+ *
+ * @param db the DB implementation to use
+ * @param dotransactions true to do transactions, false to insert data
+ * @param workload the workload to use
+ * @param threadid the id of this thread
+ * @param threadcount the total number of threads
+ * @param props the properties defining the experiment
+ * @param opcount the number of operations (transactions or inserts) to do
+ * @param targetperthreadperms target number of operations per thread per ms
+ */
+ public ClientThread(DB db, boolean dotransactions, Workload workload, int threadid, int threadcount, Properties props, int opcount, double targetperthreadperms)
+ {
+ //TODO: consider removing threadcount and threadid
+ _db=db;
+ _dotransactions=dotransactions;
+ _workload=workload;
+ _opcount=opcount;
+ _opsdone=0;
+ _target=targetperthreadperms;
+ _threadid=threadid;
+ _threadcount=threadcount;
+ _props=props;
+ //System.out.println("Interval = "+interval);
+ }
+
+ public int getOpsDone()
+ {
+ return _opsdone;
+ }
+
+ public void run()
+ {
+ try
+ {
+ _db.init();
+ }
+ catch (DBException e)
+ {
+ e.printStackTrace();
+ e.printStackTrace(System.out);
+ return;
+ }
+
+ try
+ {
+ _workloadstate=_workload.initThread(_props,_threadid,_threadcount);
+ }
+ catch (WorkloadException e)
+ {
+ e.printStackTrace();
+ e.printStackTrace(System.out);
+ return;
+ }
+
+ //spread the thread operations out so they don't all hit the DB at the same time
+ try
+ {
+ //GH issue 4 - throws exception if _target>1 because random.nextInt argument must be >0
+ //and the sleep() doesn't make sense for granularities < 1 ms anyway
+ if ( (_target>0) && (_target<=1.0) )
+ {
+ sleep(Utils.random().nextInt((int)(1.0/_target)));
+ }
+ }
+ catch (InterruptedException e)
+ {
+ // do nothing.
+ }
+
+ try
+ {
+ if (_dotransactions)
+ {
+ long st=System.currentTimeMillis();
+
+ while (((_opcount == 0) || (_opsdone < _opcount)) && !_workload.isStopRequested())
+ {
+
+ if (!_workload.doTransaction(_db,_workloadstate))
+ {
+ break;
+ }
+
+ _opsdone++;
+
+ //throttle the operations
+ if (_target>0)
+ {
+ //this is more accurate than other throttling approaches we have tried,
+ //like sleeping for (1/target throughput)-operation latency,
+ //because it smooths timing inaccuracies (from sleep() taking an int,
+ //current time in millis) over many operations
+ while (System.currentTimeMillis()-st<((double)_opsdone)/_target)
+ {
+ try
+ {
+ sleep(1);
+ }
+ catch (InterruptedException e)
+ {
+ // do nothing.
+ }
+
+ }
+ }
+ }
+ }
+ else
+ {
+ long st=System.currentTimeMillis();
+
+ while (((_opcount == 0) || (_opsdone < _opcount)) && !_workload.isStopRequested())
+ {
+
+ if (!_workload.doInsert(_db,_workloadstate))
+ {
+ break;
+ }
+
+ _opsdone++;
+
+ //throttle the operations
+ if (_target>0)
+ {
+ //this is more accurate than other throttling approaches we have tried,
+ //like sleeping for (1/target throughput)-operation latency,
+ //because it smooths timing inaccuracies (from sleep() taking an int,
+ //current time in millis) over many operations
+ while (System.currentTimeMillis()-st<((double)_opsdone)/_target)
+ {
+ try
+ {
+ sleep(1);
+ }
+ catch (InterruptedException e)
+ {
+ // do nothing.
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ e.printStackTrace(System.out);
+ System.exit(0);
+ }
+
+ try
+ {
+ _db.cleanup();
+ }
+ catch (DBException e)
+ {
+ e.printStackTrace();
+ e.printStackTrace(System.out);
+ return;
+ }
+ }
+}
+
+/**
+ * Main class for executing YCSB.
+ */
+public class Client
+{
+
+ public static final String OPERATION_COUNT_PROPERTY="operationcount";
+
+ public static final String RECORD_COUNT_PROPERTY="recordcount";
+
+ public static final String WORKLOAD_PROPERTY="workload";
+
+ /**
+ * Indicates how many inserts to do, if less than recordcount. Useful for partitioning
+ * the load among multiple servers, if the client is the bottleneck. Additionally, workloads
+ * should support the "insertstart" property, which tells them which record to start at.
+ */
+ public static final String INSERT_COUNT_PROPERTY="insertcount";
+
+ /**
+ * The maximum amount of time (in seconds) for which the benchmark will be run.
+ */
+ public static final String MAX_EXECUTION_TIME = "maxexecutiontime";
+
+ public static void usageMessage()
+ {
+ System.out.println("Usage: java com.yahoo.ycsb.Client [options]");
+ System.out.println("Options:");
+ System.out.println(" -threads n: execute using n threads (default: 1) - can also be specified as the \n" +
+ " \"threadcount\" property using -p");
+ System.out.println(" -target n: attempt to do n operations per second (default: unlimited) - can also\n" +
+ " be specified as the \"target\" property using -p");
+ System.out.println(" -load: run the loading phase of the workload");
+ System.out.println(" -t: run the transactions phase of the workload (default)");
+ System.out.println(" -db dbname: specify the name of the DB to use (default: com.yahoo.ycsb.BasicDB) - \n" +
+ " can also be specified as the \"db\" property using -p");
+ System.out.println(" -P propertyfile: load properties from the given file. Multiple files can");
+ System.out.println(" be specified, and will be processed in the order specified");
+ System.out.println(" -p name=value: specify a property to be passed to the DB and workloads;");
+ System.out.println(" multiple properties can be specified, and override any");
+ System.out.println(" values in the propertyfile");
+ System.out.println(" -s: show status during run (default: no status)");
+ System.out.println(" -l label: use label for status (e.g. to label one experiment out of a whole batch)");
+ System.out.println("");
+ System.out.println("Required properties:");
+ System.out.println(" "+WORKLOAD_PROPERTY+": the name of the workload class to use (e.g. com.yahoo.ycsb.workloads.CoreWorkload)");
+ System.out.println("");
+ System.out.println("To run the transaction phase from multiple servers, start a separate client on each.");
+ System.out.println("To run the load phase from multiple servers, start a separate client on each; additionally,");
+ System.out.println("use the \"insertcount\" and \"insertstart\" properties to divide up the records to be inserted");
+ }
+
+ public static boolean checkRequiredProperties(Properties props)
+ {
+ if (props.getProperty(WORKLOAD_PROPERTY)==null)
+ {
+ System.out.println("Missing property: "+WORKLOAD_PROPERTY);
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Exports the measurements to either sysout or a file using the exporter
+ * loaded from conf.
+ * @throws IOException Either failed to write to output stream or failed to close it.
+ */
+ private static void exportMeasurements(Properties props, int opcount, long runtime)
+ throws IOException
+ {
+ MeasurementsExporter exporter = null;
+ try
+ {
+ // if no destination file is provided the results will be written to stdout
+ OutputStream out;
+ String exportFile = props.getProperty("exportfile");
+ if (exportFile == null)
+ {
+ out = System.out;
+ } else
+ {
+ out = new FileOutputStream(exportFile);
+ }
+
+ // if no exporter is provided the default text one will be used
+ String exporterStr = props.getProperty("exporter", "com.yahoo.ycsb.measurements.exporter.TextMeasurementsExporter");
+ try
+ {
+ exporter = (MeasurementsExporter) Class.forName(exporterStr).getConstructor(OutputStream.class).newInstance(out);
+ } catch (Exception e)
+ {
+ System.err.println("Could not find exporter " + exporterStr
+ + ", will use default text reporter.");
+ e.printStackTrace();
+ exporter = new TextMeasurementsExporter(out);
+ }
+
+ exporter.write("OVERALL", "RunTime(ms)", runtime);
+ double throughput = 1000.0 * ((double) opcount) / ((double) runtime);
+ exporter.write("OVERALL", "Throughput(ops/sec)", throughput);
+
+ Measurements.getMeasurements().exportMeasurements(exporter);
+ } finally
+ {
+ if (exporter != null)
+ {
+ exporter.close();
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void main(String[] args)
+ {
+ String dbname;
+ Properties props=new Properties();
+ Properties fileprops=new Properties();
+ boolean dotransactions=true;
+ int threadcount=1;
+ int target=0;
+ boolean status=false;
+ String label="";
+
+ //parse arguments
+ int argindex=0;
+
+ if (args.length==0)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+
+ while (args[argindex].startsWith("-"))
+ {
+ if (args[argindex].compareTo("-threads")==0)
+ {
+ argindex++;
+ if (argindex>=args.length)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+ int tcount=Integer.parseInt(args[argindex]);
+ props.setProperty("threadcount", tcount+"");
+ argindex++;
+ }
+ else if (args[argindex].compareTo("-target")==0)
+ {
+ argindex++;
+ if (argindex>=args.length)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+ int ttarget=Integer.parseInt(args[argindex]);
+ props.setProperty("target", ttarget+"");
+ argindex++;
+ }
+ else if (args[argindex].compareTo("-load")==0)
+ {
+ dotransactions=false;
+ argindex++;
+ }
+ else if (args[argindex].compareTo("-t")==0)
+ {
+ dotransactions=true;
+ argindex++;
+ }
+ else if (args[argindex].compareTo("-s")==0)
+ {
+ status=true;
+ argindex++;
+ }
+ else if (args[argindex].compareTo("-db")==0)
+ {
+ argindex++;
+ if (argindex>=args.length)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+ props.setProperty("db",args[argindex]);
+ argindex++;
+ }
+ else if (args[argindex].compareTo("-l")==0)
+ {
+ argindex++;
+ if (argindex>=args.length)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+ label=args[argindex];
+ argindex++;
+ }
+ else if (args[argindex].compareTo("-P")==0)
+ {
+ argindex++;
+ if (argindex>=args.length)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+ String propfile=args[argindex];
+ argindex++;
+
+ Properties myfileprops=new Properties();
+ try
+ {
+ myfileprops.load(new FileInputStream(propfile));
+ }
+ catch (IOException e)
+ {
+ System.out.println(e.getMessage());
+ System.exit(0);
+ }
+
+ //Issue #5 - remove call to stringPropertyNames to make compilable under Java 1.5
+ for (Enumeration e=myfileprops.propertyNames(); e.hasMoreElements(); )
+ {
+ String prop=(String)e.nextElement();
+
+ fileprops.setProperty(prop,myfileprops.getProperty(prop));
+ }
+
+ }
+ else if (args[argindex].compareTo("-p")==0)
+ {
+ argindex++;
+ if (argindex>=args.length)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+ int eq=args[argindex].indexOf('=');
+ if (eq<0)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+
+ String name=args[argindex].substring(0,eq);
+ String value=args[argindex].substring(eq+1);
+ props.put(name,value);
+ //System.out.println("["+name+"]=["+value+"]");
+ argindex++;
+ }
+ else
+ {
+ System.out.println("Unknown option "+args[argindex]);
+ usageMessage();
+ System.exit(0);
+ }
+
+ if (argindex>=args.length)
+ {
+ break;
+ }
+ }
+
+ if (argindex!=args.length)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+
+ //set up logging
+ //BasicConfigurator.configure();
+
+ //overwrite file properties with properties from the command line
+
+ //Issue #5 - remove call to stringPropertyNames to make compilable under Java 1.5
+ for (Enumeration e=props.propertyNames(); e.hasMoreElements(); )
+ {
+ String prop=(String)e.nextElement();
+
+ fileprops.setProperty(prop,props.getProperty(prop));
+ }
+
+ props=fileprops;
+
+ if (!checkRequiredProperties(props))
+ {
+ System.exit(0);
+ }
+
+ long maxExecutionTime = Integer.parseInt(props.getProperty(MAX_EXECUTION_TIME, "0"));
+
+ //get number of threads, target and db
+ threadcount=Integer.parseInt(props.getProperty("threadcount","1"));
+ dbname=props.getProperty("db","com.yahoo.ycsb.BasicDB");
+ target=Integer.parseInt(props.getProperty("target","0"));
+
+ //compute the target throughput
+ double targetperthreadperms=-1;
+ if (target>0)
+ {
+ double targetperthread=((double)target)/((double)threadcount);
+ targetperthreadperms=targetperthread/1000.0;
+ }
+
+ System.out.println("YCSB Client 0.1");
+ System.out.print("Command line:");
+ for (int i=0; i<args.length; i++)
+ {
+ System.out.print(" "+args[i]);
+ }
+ System.out.println();
+ System.err.println("Loading workload...");
+
+ //show a warning message that creating the workload is taking a while
+ //but only do so if it is taking longer than 2 seconds
+ //(showing the message right away if the setup wasn't taking very long was confusing people)
+ Thread warningthread=new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ sleep(2000);
+ }
+ catch (InterruptedException e)
+ {
+ return;
+ }
+ System.err.println(" (might take a few minutes for large data sets)");
+ }
+ };
+
+ warningthread.start();
+
+ //set up measurements
+ Measurements.setProperties(props);
+
+ //load the workload
+ ClassLoader classLoader = Client.class.getClassLoader();
+
+ Workload workload=null;
+
+ try
+ {
+ Class workloadclass = classLoader.loadClass(props.getProperty(WORKLOAD_PROPERTY));
+
+ workload=(Workload)workloadclass.newInstance();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ e.printStackTrace(System.out);
+ System.exit(0);
+ }
+
+ try
+ {
+ workload.init(props);
+ }
+ catch (WorkloadException e)
+ {
+ e.printStackTrace();
+ e.printStackTrace(System.out);
+ System.exit(0);
+ }
+
+ warningthread.interrupt();
+
+ //run the workload
+
+ System.err.println("Starting test.");
+
+ int opcount;
+ if (dotransactions)
+ {
+ opcount=Integer.parseInt(props.getProperty(OPERATION_COUNT_PROPERTY,"0"));
+ }
+ else
+ {
+ if (props.containsKey(INSERT_COUNT_PROPERTY))
+ {
+ opcount=Integer.parseInt(props.getProperty(INSERT_COUNT_PROPERTY,"0"));
+ }
+ else
+ {
+ opcount=Integer.parseInt(props.getProperty(RECORD_COUNT_PROPERTY,"0"));
+ }
+ }
+
+ Vector<Thread> threads=new Vector<Thread>();
+
+ for (int threadid=0; threadid<threadcount; threadid++)
+ {
+ DB db=null;
+ try
+ {
+ db=DBFactory.newDB(dbname,props);
+ }
+ catch (UnknownDBException e)
+ {
+ System.out.println("Unknown DB "+dbname);
+ System.exit(0);
+ }
+
+ Thread t=new ClientThread(db,dotransactions,workload,threadid,threadcount,props,opcount/threadcount,targetperthreadperms);
+
+ threads.add(t);
+ //t.start();
+ }
+
+ StatusThread statusthread=null;
+
+ if (status)
+ {
+ boolean standardstatus=false;
+ if (props.getProperty("measurementtype","").compareTo("timeseries")==0)
+ {
+ standardstatus=true;
+ }
+ statusthread=new StatusThread(threads,label,standardstatus);
+ statusthread.start();
+ }
+
+ long st=System.currentTimeMillis();
+
+ for (Thread t : threads)
+ {
+ t.start();
+ }
+
+ Thread terminator = null;
+
+ if (maxExecutionTime > 0) {
+ terminator = new TerminatorThread(maxExecutionTime, threads, workload);
+ terminator.start();
+ }
+
+ int opsDone = 0;
+
+ for (Thread t : threads)
+ {
+ try
+ {
+ t.join();
+ opsDone += ((ClientThread)t).getOpsDone();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+
+ long en=System.currentTimeMillis();
+
+ if (terminator != null && !terminator.isInterrupted()) {
+ terminator.interrupt();
+ }
+
+ if (status)
+ {
+ statusthread.interrupt();
+ }
+
+ try
+ {
+ workload.cleanup();
+ }
+ catch (WorkloadException e)
+ {
+ e.printStackTrace();
+ e.printStackTrace(System.out);
+ System.exit(0);
+ }
+
+ try
+ {
+ exportMeasurements(props, opsDone, en - st);
+ } catch (IOException e)
+ {
+ System.err.println("Could not export measurements, error: " + e.getMessage());
+ e.printStackTrace();
+ System.exit(-1);
+ }
+
+ System.exit(0);
+ }
+}
View
410 core/src/main/java/com/yahoo/ycsb/CommandLine.java
@@ -0,0 +1,410 @@
+/**
+ * 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.Properties;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Vector;
+
+import com.yahoo.ycsb.workloads.*;
+
+/**
+ * A simple command line client to a database, using the appropriate com.yahoo.ycsb.DB implementation.
+ */
+public class CommandLine
+{
+ public static final String DEFAULT_DB="com.yahoo.ycsb.BasicDB";
+
+ public static void usageMessage()
+ {
+ System.out.println("YCSB Command Line Client");
+ System.out.println("Usage: java com.yahoo.ycsb.CommandLine [options]");
+ System.out.println("Options:");
+ System.out.println(" -P filename: Specify a property file");
+ System.out.println(" -p name=value: Specify a property value");
+ System.out.println(" -db classname: Use a specified DB class (can also set the \"db\" property)");
+ System.out.println(" -table tablename: Use the table name instead of the default \""+CoreWorkload.TABLENAME_PROPERTY_DEFAULT+"\"");
+ System.out.println();
+ }
+
+ public static void help()
+ {
+ System.out.println("Commands:");
+ System.out.println(" read key [field1 field2 ...] - Read a record");
+ System.out.println(" scan key recordcount [field1 field2 ...] - Scan starting at key");
+ System.out.println(" insert key name1=value1 [name2=value2 ...] - Insert a new record");
+ System.out.println(" update key name1=value1 [name2=value2 ...] - Update a record");
+ System.out.println(" delete key - Delete a record");
+ System.out.println(" table [tablename] - Get or [set] the name of the table");
+ System.out.println(" quit - Quit");
+ }
+
+ public static void main(String[] args)
+ {
+ int argindex=0;
+
+ Properties props=new Properties();
+ Properties fileprops=new Properties();
+ String table=CoreWorkload.TABLENAME_PROPERTY_DEFAULT;
+
+ while ( (argindex<args.length) && (args[argindex].startsWith("-")) )
+ {
+ if ( (args[argindex].compareTo("-help")==0) ||
+ (args[argindex].compareTo("--help")==0) ||
+ (args[argindex].compareTo("-?")==0) ||
+ (args[argindex].compareTo("--?")==0) )
+ {
+ usageMessage();
+ System.exit(0);
+ }
+
+ if (args[argindex].compareTo("-db")==0)
+ {
+ argindex++;
+ if (argindex>=args.length)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+ props.setProperty("db",args[argindex]);
+ argindex++;
+ }
+ else if (args[argindex].compareTo("-P")==0)
+ {
+ argindex++;
+ if (argindex>=args.length)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+ String propfile=args[argindex];
+ argindex++;
+
+ Properties myfileprops=new Properties();
+ try
+ {
+ myfileprops.load(new FileInputStream(propfile));
+ }
+ catch (IOException e)
+ {
+ System.out.println(e.getMessage());
+ System.exit(0);
+ }
+
+ for (Enumeration e=myfileprops.propertyNames(); e.hasMoreElements(); )
+ {
+ String prop=(String)e.nextElement();
+
+ fileprops.setProperty(prop,myfileprops.getProperty(prop));
+ }
+
+ }
+ else if (args[argindex].compareTo("-p")==0)
+ {
+ argindex++;
+ if (argindex>=args.length)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+ int eq=args[argindex].indexOf('=');
+ if (eq<0)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+
+ String name=args[argindex].substring(0,eq);
+ String value=args[argindex].substring(eq+1);
+ props.put(name,value);
+ //System.out.println("["+name+"]=["+value+"]");
+ argindex++;
+ }
+ else if (args[argindex].compareTo("-table")==0)
+ {
+ argindex++;
+ if (argindex>=args.length)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+ table=args[argindex];
+ argindex++;
+ }
+ else
+ {
+ System.out.println("Unknown option "+args[argindex]);
+ usageMessage();
+ System.exit(0);
+ }
+
+ if (argindex>=args.length)
+ {
+ break;
+ }
+ }
+
+ if (argindex!=args.length)
+ {
+ usageMessage();
+ System.exit(0);
+ }
+
+ for (Enumeration e=props.propertyNames(); e.hasMoreElements(); )
+ {
+ String prop=(String)e.nextElement();
+
+ fileprops.setProperty(prop,props.getProperty(prop));
+ }
+
+ props=fileprops;
+
+ System.out.println("YCSB Command Line client");
+ System.out.println("Type \"help\" for command line help");
+ System.out.println("Start with \"-help\" for usage info");
+
+ //create a DB
+ String dbname=props.getProperty("db",DEFAULT_DB);
+
+ ClassLoader classLoader = CommandLine.class.getClassLoader();
+
+ DB db=null;
+
+ try
+ {
+ Class dbclass = classLoader.loadClass(dbname);
+ db=(DB)dbclass.newInstance();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ System.exit(0);
+ }
+
+ db.setProperties(props);
+ try
+ {
+ db.init();
+ }
+ catch (DBException e)
+ {
+ e.printStackTrace();
+ System.exit(0);
+ }
+
+ System.out.println("Connected.");
+
+ //main loop
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+
+ for (;;)
+ {
+ //get user input
+ System.out.print("> ");
+
+ String input=null;
+
+ try
+ {
+ input=br.readLine();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ if (input.compareTo("")==0)
+ {
+ continue;
+ }
+
+ if (input.compareTo("help")==0)
+ {
+ help();
+ continue;
+ }
+
+ if (input.compareTo("quit")==0)
+ {
+ break;
+ }
+
+ String[] tokens=input.split(" ");
+
+ long st=System.currentTimeMillis();
+ //handle commands
+ if (tokens[0].compareTo("table")==0)
+ {
+ if (tokens.length==1)
+ {
+ System.out.println("Using table \""+table+"\"");
+ }
+ else if (tokens.length==2)
+ {
+ table=tokens[1];
+ System.out.println("Using table \""+table+"\"");
+ }
+ else
+ {
+ System.out.println("Error: syntax is \"table tablename\"");
+ }
+ }
+ else if (tokens[0].compareTo("read")==0)
+ {
+ if (tokens.length==1)
+ {
+ System.out.println("Error: syntax is \"read keyname [field1 field2 ...]\"");
+ }
+ else
+ {
+ Set<String> fields=null;
+
+ if (tokens.length>2)
+ {
+ fields=new HashSet<String>();
+
+ for (int i=2; i<tokens.length; i++)
+ {
+ fields.add(tokens[i]);
+ }
+ }
+
+ 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,ByteIterator> ent : result.entrySet())
+ {
+ System.out.println(ent.getKey()+"="+ent.getValue());
+ }
+ }
+ }
+ else if (tokens[0].compareTo("scan")==0)
+ {
+ if (tokens.length<3)
+ {
+ System.out.println("Error: syntax is \"scan keyname scanlength [field1 field2 ...]\"");
+ }
+ else
+ {
+ Set<String> fields=null;
+
+ if (tokens.length>3)
+ {
+ fields=new HashSet<String>();
+
+ for (int i=3; i<tokens.length; i++)
+ {
+ fields.add(tokens[i]);
+ }
+ }
+
+ 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;
+ if (results.size()==0)
+ {
+ System.out.println("0 records");
+ }
+ else
+ {
+ System.out.println("--------------------------------");
+ }
+ for (HashMap<String,ByteIterator> result : results)
+ {
+ System.out.println("Record "+(record++));
+ for (Map.Entry<String,ByteIterator> ent : result.entrySet())
+ {
+ System.out.println(ent.getKey()+"="+ent.getValue());
+ }
+ System.out.println("--------------------------------");
+ }
+ }
+ }
+ else if (tokens[0].compareTo("update")==0)
+ {
+ if (tokens.length<3)
+ {
+ System.out.println("Error: syntax is \"update keyname name1=value1 [name2=value2 ...]\"");
+ }
+ else
+ {
+ 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],new StringByteIterator(nv[1]));
+ }
+
+ int ret=db.update(table,tokens[1],values);
+ System.out.println("Return code: "+ret);
+ }
+ }
+ else if (tokens[0].compareTo("insert")==0)
+ {
+ if (tokens.length<3)
+ {
+ System.out.println("Error: syntax is \"insert keyname name1=value1 [name2=value2 ...]\"");
+ }
+ else
+ {
+ 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],new StringByteIterator(nv[1]));
+ }
+
+ int ret=db.insert(table,tokens[1],values);
+ System.out.println("Return code: "+ret);
+ }
+ }
+ else if (tokens[0].compareTo("delete")==0)
+ {
+ if (tokens.length!=2)
+ {
+ System.out.println("Error: syntax is \"delete keyname\"");
+ }
+ else
+ {
+ int ret=db.delete(table,tokens[1]);
+ System.out.println("Return code: "+ret);
+ }
+ }
+ else
+ {
+ System.out.println("Error: unknown command \""+tokens[0]+"\"");
+ }
+
+ System.out.println((System.currentTimeMillis()-st)+" ms");
+
+ }
+ }
+
+}
View
137 core/src/main/java/com/yahoo/ycsb/DB.java
@@ -0,0 +1,137 @@
+/**
+ * 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.HashMap;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Vector;
+
+/**
+ * A layer for accessing a database to be benchmarked. Each thread in the client
+ * will be given its own instance of whatever DB class is to be used in the test.
+ * This class should be constructed using a no-argument constructor, so we can
+ * load it dynamically. Any argument-based initialization should be
+ * done by init().
+ *
+ * Note that YCSB does not make any use of the return codes returned by this class.
+ * Instead, it keeps a count of the return values and presents them to the user.
+ *
+ * The semantics of methods such as insert, update and delete vary from database
+ * to database. In particular, operations may or may not be durable once these
+ * methods commit, and some systems may return 'success' regardless of whether
+ * or not a tuple with a matching key existed before the call. Rather than dictate
+ * the exact semantics of these methods, we recommend you either implement them
+ * to match the database's default semantics, or the semantics of your
+ * target application. For the sake of comparison between experiments we also
+ * recommend you explain the semantics you chose when presenting performance results.
+ */
+public abstract class DB
+{
+ /**
+ * Properties for configuring this DB.
+ */
+ Properties _p=new Properties();
+
+ /**
+ * Set the properties for this DB.
+ */
+ public void setProperties(Properties p)
+ {
+ _p=p;
+
+ }
+
+ /**
+ * Get the set of properties for this DB.
+ */
+ public Properties getProperties()
+ {
+ return _p;
+ }
+
+ /**
+ * Initialize any state for this DB.
+ * Called once per DB instance; there is one DB instance per client thread.
+ */
+ public void init() throws DBException
+ {
+ }
+
+ /**
+ * Cleanup any state for this DB.
+ * Called once per DB instance; there is one DB instance per client thread.
+ */
+ public void cleanup() throws DBException
+ {
+ }
+
+ /**
+ * Read a record from the database. Each field/value pair from the result will be stored in a HashMap.
+ *
+ * @param table The name of the table
+ * @param key The record key of the record to read.
+ * @param fields The list of fields to read, or null for all of them
+ * @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,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.
+ *
+ * @param table The name of the table
+ * @param startkey The record key of the first record to read.
+ * @param recordcount The number of records to read
+ * @param fields The list of fields to read, or null for all of them
+ * @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,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
+ * record key, overwriting any existing values with the same field name.
+ *
+ * @param table The name of the table
+ * @param key The record key of the record to write.
+ * @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,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
+ * record key.
+ *
+ * @param table The name of the table
+ * @param key The record key of the record to insert.
+ * @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,ByteIterator>