package com.rubiconproject.oss.kv.server;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;
import org.apache.thrift.transport.TTransportFactory;
import com.rubiconproject.oss.kv.KeyValueStore;
import com.rubiconproject.oss.kv.gen.Constants;
import com.rubiconproject.oss.kv.gen.GetResult;
import com.rubiconproject.oss.kv.gen.KeyValueService;
import com.rubiconproject.oss.kv.gen.KeyValueStoreException;
import com.rubiconproject.oss.kv.gen.KeyValueStoreIOException;
import com.rubiconproject.oss.kv.transcoder.ByteArrayTranscoder;
import com.rubiconproject.oss.kv.transcoder.Transcoder;
public class ThriftKeyValueServer {
private static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.wrap(new byte[0]);
private Log log = LogFactory.getLog(getClass());
private TServer server;
private KeyValueStore backend;
private int minWorkerThreads = 5;
private int maxWorkerThreads = 500;
public ThriftKeyValueServer() {
}
public ThriftKeyValueServer(KeyValueStore backend) {
this.backend = backend;
}
public void setBackend(KeyValueStore backend) {
this.backend = backend;
}
public void setMinWorkerThreads(int minWorkerThreads) {
this.minWorkerThreads = minWorkerThreads;
}
public void setMaxWorkerThreads(int maxWorkerThreads) {
this.maxWorkerThreads = maxWorkerThreads;
}
public void start() throws IOException {
log.trace("start()");
try {
KeyValueStoreServiceHandler handler = new KeyValueStoreServiceHandler(
backend);
KeyValueService.Processor processor = new KeyValueService.Processor(
handler);
TServerSocket serverTransport = new TServerSocket(
Constants.DEFAULT_PORT);
TTransportFactory tfactory = new TTransportFactory();
TProtocolFactory pfactory = new TBinaryProtocol.Factory();
// this.server = new TThreadPoolServer(processor, serverTransport,
// tfactory, pfactory);
TTransportFactory ttfactory = new TFramedTransport.Factory();
/*TThreadPoolServer.Options options = new TThreadPoolServer.Options();
options.minWorkerThreads = minWorkerThreads;
options.maxWorkerThreads = maxWorkerThreads;
this.server = new TThreadPoolServer(processor, serverTransport,
ttfactory, ttfactory, pfactory, pfactory, options);
Thread t = new Thread(new Runnable() {
public void run() {
server.serve();
}
}, "KeyValueService");
t.setDaemon(true);
t.start();*/
} catch (TTransportException e) {
log.error("TTransportException inside start()", e);
throw new IOException(e);
} finally {
}
}
private static class KeyValueStoreServiceHandler implements
KeyValueService.Iface {
private Log log = LogFactory.getLog(getClass());
private Log accessLog = LogFactory.getLog("haymitch.thrift.accesslog");
private Transcoder transcoder = new ByteArrayTranscoder();
private KeyValueStore backend;
public KeyValueStoreServiceHandler(KeyValueStore backend) {
this.backend = backend;
}
public boolean exists(String key) throws KeyValueStoreIOException,
KeyValueStoreException, TException {
log.trace("exists()");
long start = System.currentTimeMillis();
boolean success = false;
try {
boolean b = backend.exists(key);
success = true;
return b;
} catch (com.rubiconproject.oss.kv.KeyValueStoreException e) {
log.error("KeyValueStoreException inside exists()", e);
throw new KeyValueStoreException();
} catch (IOException e) {
log.error("IOException inside exists()", e);
throw new KeyValueStoreIOException();
} finally {
if (accessLog.isInfoEnabled()) {
long time = System.currentTimeMillis() - start;
accessLog.info(String.format("exists %1$s %2$d 0 %3$s",
key, time, success));
}
}
}
public GetResult getValue(String key) throws KeyValueStoreIOException,
KeyValueStoreException, TException {
log.trace("getValue()");
long start = System.currentTimeMillis();
long byteCount = 0;
boolean success = false;
try {
Object obj = backend.get(key, transcoder);
GetResult result = null;
if (obj == null) {
result = new GetResult(false, EMPTY_BYTE_BUFFER);
} else {
byte[] bytes = (byte[]) obj;
byteCount = bytes.length;
result = new GetResult(true, ByteBuffer.wrap(bytes));
}
success = true;
return result;
} catch (com.rubiconproject.oss.kv.KeyValueStoreException e) {
log.error("KeyValueStoreException inside getValue()", e);
throw new KeyValueStoreException();
} catch (IOException e) {
log.error("IOException inside getValue()", e);
throw new KeyValueStoreIOException();
} finally {
if (accessLog.isInfoEnabled()) {
long time = System.currentTimeMillis() - start;
accessLog.info(String.format("get %1$s %2$d %3$d %4$s",
key, time, byteCount, success));
}
}
}
public Map<String, GetResult> getBulk(List<String> keys)
throws KeyValueStoreIOException, KeyValueStoreException,
TException {
log.trace("getValue()");
long start = System.currentTimeMillis();
long byteCount = 0;
boolean success = false;
try {
Map<String, Object> backendResult = backend.getBulk(keys,
transcoder);
Map<String, GetResult> results = new HashMap<String, GetResult>(
backendResult.size());
for (Map.Entry<String, Object> entry : backendResult.entrySet()) {
GetResult result = new GetResult(true, ByteBuffer.wrap((byte[]) entry
.getValue()));
results.put(entry.getKey(), result);
}
success = true;
return results;
} catch (com.rubiconproject.oss.kv.KeyValueStoreException e) {
log.error("KeyValueStoreException inside getValue()", e);
throw new KeyValueStoreException();
} catch (IOException e) {
log.error("IOException inside getValue()", e);
throw new KeyValueStoreIOException();
} finally {
if (accessLog.isInfoEnabled()) {
long time = System.currentTimeMillis() - start;
accessLog.info(String.format("getbulk %1$s %2$d %3$d %4$s",
"_", time, byteCount, success));
}
}
}
public void setValue(String key, ByteBuffer data)
throws KeyValueStoreIOException, KeyValueStoreException,
TException {
log.trace("setValue()");
long start = System.currentTimeMillis();
long byteCount = 0;
boolean success = false;
try {
byte[] bytes = data.array();
backend.set(key, bytes, transcoder);
byteCount = bytes.length;
success = true;
} catch (com.rubiconproject.oss.kv.KeyValueStoreException e) {
log.error("KeyValueStoreException inside setValue()", e);
throw new KeyValueStoreException();
} catch (IOException e) {
log.error("IOException inside setValue()", e);
throw new KeyValueStoreIOException();
} finally {
if (accessLog.isInfoEnabled()) {
long time = System.currentTimeMillis() - start;
accessLog.info(String.format("set %1$s %2$d %3$d %4$s",
key, time, byteCount, success));
}
}
}
public void deleteValue(String key) throws KeyValueStoreIOException,
KeyValueStoreException, TException {
log.trace("deleteValue()");
long start = System.currentTimeMillis();
boolean success = false;
try {
backend.delete(key);
success = true;
} catch (com.rubiconproject.oss.kv.KeyValueStoreException e) {
log.error("KeyValueStoreException inside deleteValue()", e);
throw new KeyValueStoreException();
} catch (IOException e) {
log.error("IOException inside deleteValue()", e);
throw new KeyValueStoreIOException();
} finally {
if (accessLog.isInfoEnabled()) {
long time = System.currentTimeMillis() - start;
accessLog.info(String.format("delete %1$s %2$d 0 %3$s",
key, time, success));
}
}
}
}
}