// Jacob Leverich <leverich@stanford.edu>, 2011 // Memcached client for YCSB framework. // // Properties: // memcached.server=memcached.xyz.com // memcached.port=11211 package com.yahoo.ycsb.db; import java.io.IOException; import java.net.InetSocketAddress; import java.util.*; import java.util.concurrent.ExecutionException; import com.yahoo.ycsb.DBException; import com.yahoo.ycsb.ByteIterator; import com.yahoo.ycsb.ByteArrayByteIterator; import com.yahoo.ycsb.StringByteIterator; import net.spy.memcached.MemcachedClient; import net.spy.memcached.internal.OperationFuture; public class Memcached extends com.yahoo.ycsb.DB { MemcachedClient client; Properties props; public static final int OK = 0; public static final int ERROR = -1; public static final int NOT_FOUND = -2; /** * Initialize any state for this DB. Called once per DB instance; * there is one DB instance per client thread. */ public void init() throws DBException { props = getProperties(); String server = props.getProperty("memcached.server"); int port = 11211; if (server == null) throw new DBException("memcached.server param must be specified"); try { port = Integer.parseInt(props.getProperty("memcached.port")); } catch (Exception e) {} try { client = new MemcachedClient(new InetSocketAddress(server, port)); } catch (IOException 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 { if (client.isAlive()) client.shutdown(); } /** * 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 int read(String table, String key, Set<String> fields, HashMap<String,ByteIterator> result) { HashMap<String, byte[]> values = (HashMap<String, byte[]>) client.get(table + ":" + key); if (values == null) return NOT_FOUND; if (values.keySet().isEmpty()) return NOT_FOUND; if (fields == null) fields = values.keySet(); for (String k: fields) { byte[] v = values.get(k); if (v == null) return NOT_FOUND; result.put(k, new ByteArrayByteIterator(v)); } return OK; } /** * 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 int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,ByteIterator>> result) { 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. See * this class's description for a discussion of error codes. */ public int update(String table, String key, HashMap<String,ByteIterator> values) { HashMap<String, byte[]> new_values = new HashMap<String, byte[]>(); for (String k: values.keySet()) { new_values.put(k, values.get(k).toArray()); } OperationFuture<Boolean> f = client.set(table + ":" + key, 3600, new_values); try { return f.get() ? OK : ERROR; } catch (InterruptedException e) { return ERROR; } catch (ExecutionException e) { return ERROR; } } /** * 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 int insert(String table, String key, HashMap<String,ByteIterator> values) { return update(table, key, values); } /** * 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. See * this class's description for a discussion of error codes. */ public int delete(String table, String key) { client.delete(table + ":" + key); return OK; // FIXME check future } }