/** * 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.*; import java.nio.ByteBuffer; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import com.yahoo.ycsb.generator.ConstantIntegerGenerator; import com.yahoo.ycsb.generator.ExponentialGenerator; import com.yahoo.ycsb.generator.HistogramGenerator; import com.yahoo.ycsb.generator.IntegerGenerator; import edu.berkeley.lipstick.config.Config; import edu.berkeley.lipstick.copsclient.ClientConfig; import edu.berkeley.lipstick.copsclient.CopsStats; import edu.berkeley.lipstick.shim.LipstickShimExplicitCausality; import edu.berkeley.lipstick.util.DataWrapper; //XXXX if we do replication, fix the consistency levels /** * Cassandra 1.0.6 client for YCSB framework */ public class BoltOnCassandraClient10 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 LENGTH_DISTRIBUTION_PROPERTY = "bolton.explicitdistribution"; public static final String LENGTH_DISTRIBUTION_PROPERTY_EXPONENTIAL = "exponential"; public static final String LENGTH_DISTRIBUTION_PROPERTY_CONSTANT = "constant"; public static final String LENGTH_DISTRIBUTION_PROPERTY_HISTOGRAM = "histogram"; public static final String LENGTH_DISTRIBUTION_PROPERTY_DEFAULT = LENGTH_DISTRIBUTION_PROPERTY_EXPONENTIAL; public static final String EXPONENTIAL_DISTRIBUTION_GAMMA_PROPERTY = "bolton.explicitdistribution.gamma"; public static final String EXPONENTIAL_DISTRIBUTION_GAMMA_PROPERTY_DEFAULT = ".1"; public static final String CONSTANT_DISTRIBUTION_LENGTH_PROPERTY = "bolton.constantdistribution.length"; public static final String CONSTANT_DISTRIBUTION_LENGTH_PROPERTY_DEFAULT = "10"; public static final String HISTOGRAM_DISTRIBUTION_FILE_PROPERTY = "bolton.histogramdistribution.file"; public static final String HISTOGRAM_DISTRIBUTION_FILE_PROPERTY_DEFAULT = "twitter-hist.txt"; boolean _debug = false; IntegerGenerator chainLengthGenerator; int desiredChainLength = 0; int currentChainLength = 0; DataWrapper lastWrite; String _table = ""; Exception errorexception = null; static LipstickShimExplicitCausality shim = null; static long clientsIn = 0; static Lock shimLock = new ReentrantLock(); /** * Initialize any state for this DB. Called once per DB instance; there is one * DB instance per client thread. */ public void init() throws DBException { OperationRetries = Integer.parseInt(getProperties().getProperty(OPERATION_RETRY_PROPERTY, OPERATION_RETRY_PROPERTY_DEFAULT)); try { shimLock.lock(); if(shim == null) { shim = new LipstickShimExplicitCausality(); shim.open(); } clientsIn++; shimLock.unlock(); String distributionType = getProperties().getProperty(LENGTH_DISTRIBUTION_PROPERTY, LENGTH_DISTRIBUTION_PROPERTY_DEFAULT); if(distributionType.equals(LENGTH_DISTRIBUTION_PROPERTY_EXPONENTIAL)) chainLengthGenerator = new ExponentialGenerator( Double.parseDouble(getProperties() .getProperty(EXPONENTIAL_DISTRIBUTION_GAMMA_PROPERTY, EXPONENTIAL_DISTRIBUTION_GAMMA_PROPERTY_DEFAULT))); else if(distributionType.equals(LENGTH_DISTRIBUTION_PROPERTY_CONSTANT)) chainLengthGenerator = new ConstantIntegerGenerator(Integer.parseInt( getProperties().getProperty(CONSTANT_DISTRIBUTION_LENGTH_PROPERTY, CONSTANT_DISTRIBUTION_LENGTH_PROPERTY_DEFAULT))); else if(distributionType.equals(LENGTH_DISTRIBUTION_PROPERTY_HISTOGRAM)) chainLengthGenerator = new HistogramGenerator( getProperties().getProperty(HISTOGRAM_DISTRIBUTION_FILE_PROPERTY, HISTOGRAM_DISTRIBUTION_FILE_PROPERTY_DEFAULT)); //TOOD: reply many } catch (Exception te) { te.printStackTrace(); } } /** * Cleanup any state for this DB. Called once per DB instance; there is one DB * instance per client thread. */ public void cleanup() throws DBException { try { shimLock.lock(); clientsIn--; if(clientsIn == 0) shim.close(); shimLock.unlock(); } catch(Exception e) { e.printStackTrace(); } } /** * 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) { for (int i = 0; i < OperationRetries; i++) { try { DataWrapper shimRet = shim.get(key); ByteArrayByteIterator realRet = null; if(shimRet != null) realRet = new ByteArrayByteIterator((byte []) shimRet.getValue()); result.put(key, realRet); return Ok; } catch (Exception e) { e.printStackTrace(); 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) { 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) { 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(currentChainLength >= desiredChainLength) { desiredChainLength = chainLengthGenerator.nextInt(); currentChainLength = 0; lastWrite = null; } currentChainLength++; for (int i = 0; i < OperationRetries; i++) { try { DataWrapper ret = shim.put_after(key, values.get(values.keySet().iterator().next()).toArray(), lastWrite); lastWrite = ret; return Ok; } catch (Exception e) { System.out.print(e.getMessage()); e.printStackTrace(); 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) { return 0; } public static void main(String[] args) { BoltOnCassandraClient10 cli = new BoltOnCassandraClient10(); 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); res = cli.insert("usertable", "abc", vals); res = cli.insert("usertable", "bar", vals); 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", "abc", 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"); } }